diff options
Diffstat (limited to 'drivers')
633 files changed, 26025 insertions, 8097 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4a46344bf0e3..dd1eea90f67f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -3,6 +3,9 @@ # ACPI Configuration # +config ARCH_SUPPORTS_ACPI + bool + menuconfig ACPI bool "ACPI (Advanced Configuration and Power Interface) Support" depends on ARCH_SUPPORTS_ACPI @@ -40,9 +43,6 @@ menuconfig ACPI <http://www.acpi.info> <http://www.uefi.org/acpi/specs> -config ARCH_SUPPORTS_ACPI - bool - if ACPI config ACPI_LEGACY_TABLES_LOOKUP diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index c5367bf5487f..0f28a38a43ea 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -164,6 +164,7 @@ struct acpi_namespace_node { #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ #define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ +#define ANOBJ_NODE_EARLY_INIT 0x80 /* acpi_exec only: Node was create via init file (-fi) */ #define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 3825df923480..bbb3b4d1e796 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -25,14 +25,15 @@ /* Flags for acpi_ns_lookup, acpi_ns_search_and_enter */ #define ACPI_NS_NO_UPSEARCH 0 -#define ACPI_NS_SEARCH_PARENT 0x01 -#define ACPI_NS_DONT_OPEN_SCOPE 0x02 -#define ACPI_NS_NO_PEER_SEARCH 0x04 -#define ACPI_NS_ERROR_IF_FOUND 0x08 -#define ACPI_NS_PREFIX_IS_SCOPE 0x10 -#define ACPI_NS_EXTERNAL 0x20 -#define ACPI_NS_TEMPORARY 0x40 -#define ACPI_NS_OVERRIDE_IF_FOUND 0x80 +#define ACPI_NS_SEARCH_PARENT 0x0001 +#define ACPI_NS_DONT_OPEN_SCOPE 0x0002 +#define ACPI_NS_NO_PEER_SEARCH 0x0004 +#define ACPI_NS_ERROR_IF_FOUND 0x0008 +#define ACPI_NS_PREFIX_IS_SCOPE 0x0010 +#define ACPI_NS_EXTERNAL 0x0020 +#define ACPI_NS_TEMPORARY 0x0040 +#define ACPI_NS_OVERRIDE_IF_FOUND 0x0080 +#define ACPI_NS_EARLY_INIT 0x0100 /* Flags for acpi_ns_walk_namespace */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 2733cd4e418c..3374d41582b5 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -180,6 +180,8 @@ char acpi_ut_remove_leading_zeros(char **string); u8 acpi_ut_detect_hex_prefix(char **string); +void acpi_ut_remove_hex_prefix(char **string); + u8 acpi_ut_detect_octal_prefix(char **string); /* diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 556ff59bbbfc..3e5f95390f0d 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -763,7 +763,12 @@ acpi_db_command_dispatch(char *input_buffer, case CMD_DISASSEMBLE: case CMD_DISASM: +#ifdef ACPI_DISASSEMBLER (void)acpi_db_disassemble_method(acpi_gbl_db_args[1]); +#else + acpi_os_printf + ("The AML Disassembler is not configured/present\n"); +#endif break; case CMD_DUMP: @@ -872,7 +877,12 @@ acpi_db_command_dispatch(char *input_buffer, case CMD_LIST: +#ifdef ACPI_DISASSEMBLER acpi_db_disassemble_aml(acpi_gbl_db_args[1], op); +#else + acpi_os_printf + ("The AML Disassembler is not configured/present\n"); +#endif break; case CMD_LOCKS: diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c index 9fcecf104ba0..d8b7a0fe92ec 100644 --- a/drivers/acpi/acpica/dbmethod.c +++ b/drivers/acpi/acpica/dbmethod.c @@ -216,6 +216,7 @@ cleanup: acpi_ut_remove_reference(obj_desc); } +#ifdef ACPI_DISASSEMBLER /******************************************************************************* * * FUNCTION: acpi_db_disassemble_aml @@ -242,9 +243,8 @@ void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op) if (statements) { num_statements = strtoul(statements, NULL, 0); } -#ifdef ACPI_DISASSEMBLER + acpi_dm_disassemble(NULL, op, num_statements); -#endif } /******************************************************************************* @@ -317,8 +317,6 @@ acpi_status acpi_db_disassemble_method(char *name) walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE; status = acpi_ps_parse_aml(walk_state); - -#ifdef ACPI_DISASSEMBLER (void)acpi_dm_parse_deferred_ops(op); /* Now we can disassemble the method */ @@ -326,7 +324,6 @@ acpi_status acpi_db_disassemble_method(char *name) acpi_gbl_dm_opt_verbose = FALSE; acpi_dm_disassemble(NULL, op, 0); acpi_gbl_dm_opt_verbose = TRUE; -#endif acpi_ps_delete_parse_tree(op); @@ -337,6 +334,7 @@ acpi_status acpi_db_disassemble_method(char *name) acpi_ut_release_owner_id(&obj_desc->method.owner_id); return (AE_OK); } +#endif /******************************************************************************* * diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 4647aa8efecb..f2526726daf6 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -10,6 +10,7 @@ #include "amlcode.h" #include "acdebug.h" #include "acinterp.h" +#include "acparser.h" #define _COMPONENT ACPI_CA_DEBUGGER ACPI_MODULE_NAME("dbxface") @@ -262,10 +263,17 @@ acpi_db_single_step(struct acpi_walk_state *walk_state, } } - /* Now we can display it */ + /* Now we can disassemble and display it */ #ifdef ACPI_DISASSEMBLER acpi_dm_disassemble(walk_state, display_op, ACPI_UINT32_MAX); +#else + /* + * The AML Disassembler is not configured - at least we can + * display the opcode value and name + */ + acpi_os_printf("AML Opcode: %4.4X %s\n", op->common.aml_opcode, + acpi_ps_get_opcode_name(op->common.aml_opcode)); #endif if ((op->common.aml_opcode == AML_IF_OP) || diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 7c937595dfcb..30fe89545d6a 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -15,6 +15,10 @@ #include "acnamesp.h" #include "acparser.h" +#ifdef ACPI_EXEC_APP +#include "aecommon.h" +#endif + #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsfield") @@ -259,6 +263,13 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, u64 position; union acpi_parse_object *child; +#ifdef ACPI_EXEC_APP + u64 value = 0; + union acpi_operand_object *result_desc; + union acpi_operand_object *obj_desc; + char *name_path; +#endif + ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info); /* First field starts at bit zero */ @@ -391,6 +402,25 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } +#ifdef ACPI_EXEC_APP + name_path = + acpi_ns_get_external_pathname(info-> + field_node); + obj_desc = + acpi_ut_create_integer_object + (value); + if (ACPI_SUCCESS + (ae_lookup_init_file_entry + (name_path, &value))) { + acpi_ex_write_data_to_field + (obj_desc, + acpi_ns_get_attached_object + (info->field_node), + &result_desc); + } + acpi_ut_remove_reference(obj_desc); + ACPI_FREE(name_path); +#endif } } @@ -573,7 +603,9 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { flags |= ACPI_NS_TEMPORARY; } - +#ifdef ACPI_EXEC_APP + flags |= ACPI_NS_OVERRIDE_IF_FOUND; +#endif /* * Walk the list of entries in the field_list * Note: field_list can be of zero length. In this case, Arg will be NULL. diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 3de794bcf8fa..69603ba52a3a 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -528,13 +528,18 @@ acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value) status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm2_control_block); - value = (u32)value64; + if (ACPI_SUCCESS(status)) { + value = (u32)value64; + } break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm_timer_block); - value = (u32)value64; + if (ACPI_SUCCESS(status)) { + value = (u32)value64; + } + break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index fe9d46d81750..d8b8fc2ff563 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -56,14 +56,9 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - /* - * If the target sleep state is S5, clear all GPEs and fixed events too - */ - if (sleep_state == ACPI_STATE_S5) { - status = acpi_hw_clear_acpi_status(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + status = acpi_hw_clear_acpi_status(); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } acpi_gbl_system_awake_and_running = FALSE; diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 83a593e2155d..e3f10afde5ff 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -558,6 +558,14 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, (char *)¤t_node->name, current_node)); } +#ifdef ACPI_EXEC_APP + if ((status == AE_ALREADY_EXISTS) && + (this_node->flags & ANOBJ_NODE_EARLY_INIT)) { + this_node->flags &= ~ANOBJ_NODE_EARLY_INIT; + status = AE_OK; + } +#endif + #ifdef ACPI_ASL_COMPILER /* * If this ACPI name already exists within the namespace as an @@ -676,6 +684,11 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, } } } +#ifdef ACPI_EXEC_APP + if (flags & ACPI_NS_EARLY_INIT) { + this_node->flags |= ANOBJ_NODE_EARLY_INIT; + } +#endif *return_node = this_node; return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 44f35ab3347d..34fc2f7476ed 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -22,6 +22,7 @@ #include "acdispat.h" #include "amlcode.h" #include "acconvert.h" +#include "acnamesp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psloop") @@ -527,12 +528,18 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - if (walk_state->opcode == AML_SCOPE_OP) { + if (acpi_ns_opens_scope + (acpi_ps_get_opcode_info + (walk_state->opcode)->object_type)) { /* - * If the scope op fails to parse, skip the body of the - * scope op because the parse failure indicates that the - * device may not exist. + * If the scope/device op fails to parse, skip the body of + * the scope op because the parse failure indicates that + * the device may not exist. */ + ACPI_ERROR((AE_INFO, + "Skip parsing opcode %s", + acpi_ps_get_opcode_name + (walk_state->opcode))); walk_state->parser_state.aml = walk_state->aml + 1; walk_state->parser_state.aml = @@ -540,8 +547,6 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) (&walk_state->parser_state); walk_state->aml = walk_state->parser_state.aml; - ACPI_ERROR((AE_INFO, - "Skipping Scope block")); } continue; @@ -709,20 +714,20 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) } else if ((walk_state-> parse_flags & ACPI_PARSE_MODULE_LEVEL) - && status != AE_CTRL_TRANSFER - && ACPI_FAILURE(status)) { + && (ACPI_AML_EXCEPTION(status) + || status == AE_ALREADY_EXISTS + || status == AE_NOT_FOUND)) { /* - * ACPI_PARSE_MODULE_LEVEL flag means that we are currently - * loading a table by executing it as a control method. - * However, if we encounter an error while loading the table, - * we need to keep trying to load the table rather than - * aborting the table load (setting the status to AE_OK - * continues the table load). If we get a failure at this - * point, it means that the dispatcher got an error while - * processing Op (most likely an AML operand error) or a - * control method was called from module level and the - * dispatcher returned AE_CTRL_TRANSFER. In the latter case, - * leave the status alone, there's nothing wrong with it. + * ACPI_PARSE_MODULE_LEVEL flag means that we + * are currently loading a table by executing + * it as a control method. However, if we + * encounter an error while loading the table, + * we need to keep trying to load the table + * rather than aborting the table load (setting + * the status to AE_OK continues the table + * load). If we get a failure at this point, it + * means that the dispatcher got an error while + * trying to execute the Op. */ status = AE_OK; } diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 51891f9fb057..862149c8a208 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -516,9 +516,9 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, acpi_tb_check_duplication(table_desc, table_index); if (ACPI_FAILURE(status)) { if (status != AE_CTRL_TERMINATE) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, + ACPI_EXCEPTION((AE_INFO, status, "%4.4s 0x%8.8X%8.8X" - " Table is duplicated", + " Table is already loaded", acpi_ut_valid_nameseg (table_desc->signature. ascii) ? table_desc-> diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 118f3ff1fbb5..8cc4392c61f3 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -355,6 +355,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) u16 original_count; u16 new_count = 0; acpi_cpu_flags lock_flags; + char *message; ACPI_FUNCTION_NAME(ut_update_ref_count); @@ -391,6 +392,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) object, object->common.type, acpi_ut_get_object_type_name(object), new_count)); + message = "Incremement"; break; case REF_DECREMENT: @@ -420,6 +422,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) if (new_count == 0) { acpi_ut_delete_internal_obj(object); } + message = "Decrement"; break; default: @@ -436,8 +439,8 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) */ if (new_count > ACPI_MAX_REFERENCE_COUNT) { ACPI_WARNING((AE_INFO, - "Large Reference Count (0x%X) in object %p, Type=0x%.2X", - new_count, object, object->common.type)); + "Large Reference Count (0x%X) in object %p, Type=0x%.2X Operation=%s", + new_count, object, object->common.type, message)); } } diff --git a/drivers/acpi/acpica/utstrsuppt.c b/drivers/acpi/acpica/utstrsuppt.c index 954f8e3e35cd..05ff20049b87 100644 --- a/drivers/acpi/acpica/utstrsuppt.c +++ b/drivers/acpi/acpica/utstrsuppt.c @@ -231,14 +231,34 @@ char acpi_ut_remove_whitespace(char **string) u8 acpi_ut_detect_hex_prefix(char **string) { + char *initial_position = *string; + acpi_ut_remove_hex_prefix(string); + if (*string != initial_position) { + return (TRUE); /* String is past leading 0x */ + } + + return (FALSE); /* Not a hex string */ +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_remove_hex_prefix + * + * PARAMETERS: string - Pointer to input ASCII string + * + * RETURN: none + * + * DESCRIPTION: Remove a hex "0x" prefix + * + ******************************************************************************/ + +void acpi_ut_remove_hex_prefix(char **string) +{ if ((**string == ACPI_ASCII_ZERO) && (tolower((int)*(*string + 1)) == 'x')) { *string += 2; /* Go past the leading 0x */ - return (TRUE); } - - return (FALSE); /* Not a hex string */ } /******************************************************************************* diff --git a/drivers/acpi/acpica/utstrtoul64.c b/drivers/acpi/acpica/utstrtoul64.c index 8fadad242db6..5fde619a8bbd 100644 --- a/drivers/acpi/acpica/utstrtoul64.c +++ b/drivers/acpi/acpica/utstrtoul64.c @@ -218,7 +218,7 @@ u64 acpi_ut_implicit_strtoul64(char *string) * implicit conversions, and the "0x" prefix is "not allowed". * However, allow a "0x" prefix as an ACPI extension. */ - acpi_ut_detect_hex_prefix(&string); + acpi_ut_remove_hex_prefix(&string); if (!acpi_ut_remove_leading_zeros(&string)) { return_VALUE(0); diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 7c479002e798..b072cfc5f20e 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1699,7 +1699,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, { struct acpi_device *adev, *adev_dimm; struct device *dev = acpi_desc->dev; - unsigned long dsm_mask; + unsigned long dsm_mask, label_mask; const guid_t *guid; int i; int family = -1; @@ -1771,6 +1771,16 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, 1ULL << i)) set_bit(i, &nfit_mem->dsm_mask); + /* + * Prefer the NVDIMM_FAMILY_INTEL label read commands if present + * due to their better semantics handling locked capacity. + */ + label_mask = 1 << ND_CMD_GET_CONFIG_SIZE | 1 << ND_CMD_GET_CONFIG_DATA + | 1 << ND_CMD_SET_CONFIG_DATA; + if (family == NVDIMM_FAMILY_INTEL + && (dsm_mask & label_mask) == label_mask) + return 0; + if (acpi_nvdimm_has_method(adev_dimm, "_LSI") && acpi_nvdimm_has_method(adev_dimm, "_LSR")) { dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev)); @@ -2559,7 +2569,12 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc, test_bit(ARS_SHORT, &nfit_spa->ars_state) ? "short" : "long"); clear_bit(ARS_SHORT, &nfit_spa->ars_state); - set_bit(ARS_DONE, &nfit_spa->ars_state); + if (test_and_clear_bit(ARS_REQ_REDO, &nfit_spa->ars_state)) { + set_bit(ARS_SHORT, &nfit_spa->ars_state); + set_bit(ARS_REQ, &nfit_spa->ars_state); + dev_dbg(dev, "ARS: processing scrub request received while in progress\n"); + } else + set_bit(ARS_DONE, &nfit_spa->ars_state); } static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc) @@ -3256,9 +3271,10 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags) if (test_bit(ARS_FAILED, &nfit_spa->ars_state)) continue; - if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state)) + if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state)) { busy++; - else { + set_bit(ARS_REQ_REDO, &nfit_spa->ars_state); + } else { if (test_bit(ARS_SHORT, &flags)) set_bit(ARS_SHORT, &nfit_spa->ars_state); scheduled++; diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index a97ff42fe311..d1274ea2d251 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -119,6 +119,7 @@ enum nfit_dimm_notifiers { enum nfit_ars_state { ARS_REQ, + ARS_REQ_REDO, ARS_DONE, ARS_SHORT, ARS_FAILED, diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c index 7ffa74048107..22c9e374c923 100644 --- a/drivers/acpi/pmic/intel_pmic_crc.c +++ b/drivers/acpi/pmic/intel_pmic_crc.c @@ -25,16 +25,121 @@ #define PMIC_A0LOCK_REG 0xc5 static struct pmic_table power_table[] = { +/* { + .address = 0x00, + .reg = ??, + .bit = ??, + }, ** VSYS */ + { + .address = 0x04, + .reg = 0x63, + .bit = 0x00, + }, /* SYSX -> VSYS_SX */ + { + .address = 0x08, + .reg = 0x62, + .bit = 0x00, + }, /* SYSU -> VSYS_U */ + { + .address = 0x0c, + .reg = 0x64, + .bit = 0x00, + }, /* SYSS -> VSYS_S */ + { + .address = 0x10, + .reg = 0x6a, + .bit = 0x00, + }, /* V50S -> V5P0S */ + { + .address = 0x14, + .reg = 0x6b, + .bit = 0x00, + }, /* HOST -> VHOST, USB2/3 host */ + { + .address = 0x18, + .reg = 0x6c, + .bit = 0x00, + }, /* VBUS -> VBUS, USB2/3 OTG */ + { + .address = 0x1c, + .reg = 0x6d, + .bit = 0x00, + }, /* HDMI -> VHDMI */ +/* { + .address = 0x20, + .reg = ??, + .bit = ??, + }, ** S285 */ { .address = 0x24, .reg = 0x66, .bit = 0x00, - }, + }, /* X285 -> V2P85SX, camera */ +/* { + .address = 0x28, + .reg = ??, + .bit = ??, + }, ** V33A */ + { + .address = 0x2c, + .reg = 0x69, + .bit = 0x00, + }, /* V33S -> V3P3S, display/ssd/audio */ + { + .address = 0x30, + .reg = 0x68, + .bit = 0x00, + }, /* V33U -> V3P3U, SDIO wifi&bt */ +/* { + .address = 0x34 .. 0x40, + .reg = ??, + .bit = ??, + }, ** V33I, V18A, REFQ, V12A */ + { + .address = 0x44, + .reg = 0x5c, + .bit = 0x00, + }, /* V18S -> V1P8S, SOC/USB PHY/SIM */ { .address = 0x48, .reg = 0x5d, .bit = 0x00, - }, + }, /* V18X -> V1P8SX, eMMC/camara/audio */ + { + .address = 0x4c, + .reg = 0x5b, + .bit = 0x00, + }, /* V18U -> V1P8U, LPDDR */ + { + .address = 0x50, + .reg = 0x61, + .bit = 0x00, + }, /* V12X -> V1P2SX, SOC SFR */ + { + .address = 0x54, + .reg = 0x60, + .bit = 0x00, + }, /* V12S -> V1P2S, MIPI */ +/* { + .address = 0x58, + .reg = ??, + .bit = ??, + }, ** V10A */ + { + .address = 0x5c, + .reg = 0x56, + .bit = 0x00, + }, /* V10S -> V1P0S, SOC GFX */ + { + .address = 0x60, + .reg = 0x57, + .bit = 0x00, + }, /* V10X -> V1P0SX, SOC display/DDR IO/PCIe */ + { + .address = 0x64, + .reg = 0x59, + .bit = 0x00, + }, /* V105 -> V1P05S, L2 SRAM */ }; static struct pmic_table thermal_table[] = { diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index b933061b6b60..8c0a54d50d0e 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -205,6 +205,7 @@ phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id) return phys_id; } +EXPORT_SYMBOL_GPL(acpi_get_phys_id); int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id) { diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b2b9eba1d214..021ce46e2e57 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -610,7 +610,7 @@ static int marvell_enable = 1; module_param(marvell_enable, int, 0644); MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)"); -static int mobile_lpm_policy = CONFIG_SATA_MOBILE_LPM_POLICY; +static int mobile_lpm_policy = -1; module_param(mobile_lpm_policy, int, 0644); MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); @@ -1604,6 +1604,37 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); } +static void ahci_update_initial_lpm_policy(struct ata_port *ap, + struct ahci_host_priv *hpriv) +{ + int policy = CONFIG_SATA_MOBILE_LPM_POLICY; + + + /* Ignore processing for non mobile platforms */ + if (!(hpriv->flags & AHCI_HFLAG_IS_MOBILE)) + return; + + /* user modified policy via module param */ + if (mobile_lpm_policy != -1) { + policy = mobile_lpm_policy; + goto update_policy; + } + +#ifdef CONFIG_ACPI + if (policy > ATA_LPM_MED_POWER && + (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) { + if (hpriv->cap & HOST_CAP_PART) + policy = ATA_LPM_MIN_POWER_WITH_PARTIAL; + else if (hpriv->cap & HOST_CAP_SSC) + policy = ATA_LPM_MIN_POWER; + } +#endif + +update_policy: + if (policy >= ATA_LPM_UNKNOWN && policy <= ATA_LPM_MIN_POWER) + ap->target_lpm_policy = policy; +} + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int board_id = ent->driver_data; @@ -1807,10 +1838,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (ap->flags & ATA_FLAG_EM) ap->em_message_type = hpriv->em_msg_type; - if ((hpriv->flags & AHCI_HFLAG_IS_MOBILE) && - mobile_lpm_policy >= ATA_LPM_UNKNOWN && - mobile_lpm_policy <= ATA_LPM_MIN_POWER) - ap->target_lpm_policy = mobile_lpm_policy; + ahci_update_initial_lpm_policy(ap, hpriv); /* disabled/not-implemented port */ if (!(hpriv->port_map & (1 << i))) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 1609ebab4e23..6a1515f0da40 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -350,6 +350,7 @@ struct ahci_host_priv { u32 em_msg_type; /* EM message type */ bool got_runtime_pm; /* Did we do pm_runtime_get? */ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ + struct reset_control *rsts; /* Optional */ struct regulator **target_pwrs; /* Optional */ /* * If platform uses PHYs. There is a 1:1 relation between the port number and diff --git a/drivers/ata/ahci_brcm.c b/drivers/ata/ahci_brcm.c index ea430819c80b..f3d557777d82 100644 --- a/drivers/ata/ahci_brcm.c +++ b/drivers/ata/ahci_brcm.c @@ -425,7 +425,7 @@ static int brcm_ahci_probe(struct platform_device *pdev) brcm_sata_phys_enable(priv); - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); hpriv->plat_data = priv; diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c index 5ecc9d46cb54..dc78c98cb9f1 100644 --- a/drivers/ata/ahci_ceva.c +++ b/drivers/ata/ahci_ceva.c @@ -213,7 +213,7 @@ static int ceva_ahci_probe(struct platform_device *pdev) cevapriv->ahci_pdev = pdev; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c index 9b34dff64536..ebaa657f28c4 100644 --- a/drivers/ata/ahci_da850.c +++ b/drivers/ata/ahci_da850.c @@ -171,7 +171,7 @@ static int ahci_da850_probe(struct platform_device *pdev) u32 mpy; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_dm816.c b/drivers/ata/ahci_dm816.c index fbd827c3a75c..89509c3efb01 100644 --- a/drivers/ata/ahci_dm816.c +++ b/drivers/ata/ahci_dm816.c @@ -148,7 +148,7 @@ static int ahci_dm816_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 6822e2f33f7e..b00799d208f5 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -1127,7 +1127,7 @@ static int imx_ahci_probe(struct platform_device *pdev) return ret; } - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c index 0ae6971c2a4c..8bc1a26ffc31 100644 --- a/drivers/ata/ahci_mtk.c +++ b/drivers/ata/ahci_mtk.c @@ -142,7 +142,7 @@ static int mtk_ahci_probe(struct platform_device *pdev) if (!plat) return -ENOMEM; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 72d90b4c3aae..f9cb51be38eb 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -158,7 +158,7 @@ static int ahci_mvebu_probe(struct platform_device *pdev) const struct mbus_dram_target_info *dram; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 99f9a895a459..46f0bd75eff7 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -43,7 +43,8 @@ static int ahci_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, + AHCI_PLATFORM_GET_RESETS); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); @@ -75,7 +76,6 @@ static const struct of_device_id ahci_of_match[] = { { .compatible = "generic-ahci", }, /* Keep the following compatibles for device tree compatibility */ { .compatible = "snps,spear-ahci", }, - { .compatible = "snps,exynos5440-ahci", }, { .compatible = "ibm,476gtr-ahci", }, { .compatible = "snps,dwc-ahci", }, { .compatible = "hisilicon,hisi-ahci", }, diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index cfdef4d44ae9..ce59253ec158 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -250,7 +250,7 @@ static int ahci_qoriq_probe(struct platform_device *pdev) struct resource *res; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c index 1d31c0c0fc20..e57b6f92c288 100644 --- a/drivers/ata/ahci_seattle.c +++ b/drivers/ata/ahci_seattle.c @@ -164,7 +164,7 @@ static int ahci_seattle_probe(struct platform_device *pdev) int rc; struct ahci_host_priv *hpriv; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index bc345f249555..21c5c44832ef 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -156,7 +156,7 @@ static int st_ahci_probe(struct platform_device *pdev) if (!drv_data) return -ENOMEM; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); hpriv->plat_data = drv_data; diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index b26437430163..631610b72aa5 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -181,7 +181,7 @@ static int ahci_sunxi_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index 64d848409fe2..004f2608818e 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -494,7 +494,7 @@ static int tegra_ahci_probe(struct platform_device *pdev) int ret; unsigned int i; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index ad58da7c9aff..7e157e1bf65e 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -759,7 +759,7 @@ static int xgene_ahci_probe(struct platform_device *pdev) &xgene_ahci_v2_port_info }; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 09620c2ffa0f..b5f57c69c487 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -801,6 +801,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, cmd |= PORT_CMD_ALPE; if (policy == ATA_LPM_MIN_POWER) cmd |= PORT_CMD_ASP; + else if (policy == ATA_LPM_MIN_POWER_WITH_PARTIAL) + cmd &= ~PORT_CMD_ASP; /* write out new cmd value */ writel(cmd, port_mmio + PORT_CMD); @@ -811,7 +813,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, if ((hpriv->cap2 & HOST_CAP2_SDS) && (hpriv->cap2 & HOST_CAP2_SADM) && (link->device->flags & ATA_DFLAG_DEVSLP)) { - if (policy == ATA_LPM_MIN_POWER) + if (policy == ATA_LPM_MIN_POWER || + policy == ATA_LPM_MIN_POWER_WITH_PARTIAL) ahci_set_aggressive_devslp(ap, true); else ahci_set_aggressive_devslp(ap, false); @@ -2107,7 +2110,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) struct ahci_host_priv *hpriv = ap->host->private_data; void __iomem *port_mmio = ahci_port_base(ap); struct ata_device *dev = ap->link.device; - u32 devslp, dm, dito, mdat, deto; + u32 devslp, dm, dito, mdat, deto, dito_conf; int rc; unsigned int err_mask; @@ -2131,8 +2134,15 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) return; } - /* device sleep was already enabled */ - if (devslp & PORT_DEVSLP_ADSE) + dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; + dito = devslp_idle_timeout / (dm + 1); + if (dito > 0x3ff) + dito = 0x3ff; + + dito_conf = (devslp >> PORT_DEVSLP_DITO_OFFSET) & 0x3FF; + + /* device sleep was already enabled and same dito */ + if ((devslp & PORT_DEVSLP_ADSE) && (dito_conf == dito)) return; /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ @@ -2140,11 +2150,6 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) if (rc) return; - dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; - dito = devslp_idle_timeout / (dm + 1); - if (dito > 0x3ff) - dito = 0x3ff; - /* Use the nominal value 10 ms if the read MDAT is zero, * the nominal value of DETO is 20 ms. */ @@ -2162,6 +2167,8 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) deto = 20; } + /* Make dito, mdat, deto bits to 0s */ + devslp &= ~GENMASK_ULL(24, 2); devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) | (mdat << PORT_DEVSLP_MDAT_OFFSET) | (deto << PORT_DEVSLP_DETO_OFFSET) | @@ -2439,6 +2446,8 @@ static void ahci_port_stop(struct ata_port *ap) * re-enabling INTx. */ writel(1 << ap->port_no, host_mmio + HOST_IRQ_STAT); + + ahci_rpm_put_port(ap); } void ahci_print_info(struct ata_host *host, const char *scc_s) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 30cc8f1a31e1..c92c10d55374 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -25,6 +25,7 @@ #include <linux/phy/phy.h> #include <linux/pm_runtime.h> #include <linux/of_platform.h> +#include <linux/reset.h> #include "ahci.h" static void ahci_host_stop(struct ata_host *host); @@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators); * following order: * 1) Regulator * 2) Clocks (through ahci_platform_enable_clks) - * 3) Phys + * 3) Resets + * 4) Phys * * If resource enabling fails at any point the previous enabled resources * are disabled in reverse order. @@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) if (rc) goto disable_regulator; - rc = ahci_platform_enable_phys(hpriv); + rc = reset_control_deassert(hpriv->rsts); if (rc) goto disable_clks; + rc = ahci_platform_enable_phys(hpriv); + if (rc) + goto disable_resets; + return 0; +disable_resets: + reset_control_assert(hpriv->rsts); + disable_clks: ahci_platform_disable_clks(hpriv); @@ -238,13 +247,16 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); * This function disables all ahci_platform managed resources in the * following order: * 1) Phys - * 2) Clocks (through ahci_platform_disable_clks) - * 3) Regulator + * 2) Resets + * 3) Clocks (through ahci_platform_disable_clks) + * 4) Regulator */ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) { ahci_platform_disable_phys(hpriv); + reset_control_assert(hpriv->rsts); + ahci_platform_disable_clks(hpriv); ahci_platform_disable_regulators(hpriv); @@ -332,6 +344,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, /** * ahci_platform_get_resources - Get platform resources * @pdev: platform device to get resources for + * @flags: bitmap representing the resource to get * * This function allocates an ahci_host_priv struct, and gets the following * resources, storing a reference to them inside the returned struct: @@ -340,18 +353,20 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, * 2) regulator for controlling the targets power (optional) * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, * or for non devicetree enabled platforms a single clock - * 4) phys (optional) + * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional) + * 5) phys (optional) * * RETURNS: * The allocated ahci_host_priv on success, otherwise an ERR_PTR value */ -struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) +struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev, + unsigned int flags) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; struct clk *clk; struct device_node *child; - int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes; + int i, enabled_ports = 0, rc = -ENOMEM, child_nodes; u32 mask_port_map = 0; if (!devres_open_group(dev, NULL, GFP_KERNEL)) @@ -393,6 +408,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) hpriv->clks[i] = clk; } + if (flags & AHCI_PLATFORM_GET_RESETS) { + hpriv->rsts = devm_reset_control_array_get_optional_shared(dev); + if (IS_ERR(hpriv->rsts)) { + rc = PTR_ERR(hpriv->rsts); + goto err_out; + } + } + hpriv->nports = child_nodes = of_get_child_count(dev->of_node); /* @@ -403,14 +426,16 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) if (!child_nodes) hpriv->nports = 1; - sz = hpriv->nports * sizeof(*hpriv->phys); - hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL); + hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL); if (!hpriv->phys) { rc = -ENOMEM; goto err_out; } - sz = hpriv->nports * sizeof(*hpriv->target_pwrs); - hpriv->target_pwrs = kzalloc(sz, GFP_KERNEL); + /* + * We cannot use devm_ here, since ahci_platform_put_resources() uses + * target_pwrs after devm_ have freed memory + */ + hpriv->target_pwrs = kcalloc(hpriv->nports, sizeof(*hpriv->target_pwrs), GFP_KERNEL); if (!hpriv->target_pwrs) { rc = -ENOMEM; goto err_out; @@ -605,7 +630,7 @@ static void ahci_host_stop(struct ata_host *host) /** * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports - * @dev: platform device pointer for the host + * @pdev: platform device pointer for the host * * This function is called during system shutdown and performs the minimal * deconfiguration required to ensure that an ahci_platform host cannot diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 984b37647b2f..172e32840256 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3970,6 +3970,7 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, scontrol |= (0x6 << 8); break; case ATA_LPM_MED_POWER_WITH_DIPM: + case ATA_LPM_MIN_POWER_WITH_PARTIAL: case ATA_LPM_MIN_POWER: if (ata_link_nr_enabled(link) > 0) /* no restrictions on LPM transitions */ @@ -5066,7 +5067,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) if (n_elem < 1) return -1; - DPRINTK("%d sg elements mapped\n", n_elem); + VPRINTK("%d sg elements mapped\n", n_elem); qc->orig_n_elem = qc->n_elem; qc->n_elem = n_elem; qc->flags |= ATA_QCFLAG_DMAMAP; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8e270962b2f3..1984fc78c750 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -110,6 +110,7 @@ static const char *ata_lpm_policy_names[] = { [ATA_LPM_MAX_POWER] = "max_performance", [ATA_LPM_MED_POWER] = "medium_power", [ATA_LPM_MED_POWER_WITH_DIPM] = "med_power_with_dipm", + [ATA_LPM_MIN_POWER_WITH_PARTIAL] = "min_power_with_partial", [ATA_LPM_MIN_POWER] = "min_power", }; @@ -4288,10 +4289,10 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) static inline void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd) { -#ifdef ATA_DEBUG +#ifdef ATA_VERBOSE_DEBUG struct scsi_device *scsidev = cmd->device; - DPRINTK("CDB (%u:%d,%d,%lld) %9ph\n", + VPRINTK("CDB (%u:%d,%d,%lld) %9ph\n", ap->print_id, scsidev->channel, scsidev->id, scsidev->lun, cmd->cmnd); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index cc2f2e35f4c2..c5ea0fc635e5 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -658,36 +658,6 @@ unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc, unsigned char *buf, EXPORT_SYMBOL_GPL(ata_sff_data_xfer32); /** - * ata_sff_data_xfer_noirq - Transfer data by PIO - * @qc: queued command - * @buf: data buffer - * @buflen: buffer length - * @rw: read/write - * - * Transfer data from/to the device data register by PIO. Do the - * transfer with interrupts disabled. - * - * LOCKING: - * Inherited from caller. - * - * RETURNS: - * Bytes consumed. - */ -unsigned int ata_sff_data_xfer_noirq(struct ata_queued_cmd *qc, unsigned char *buf, - unsigned int buflen, int rw) -{ - unsigned long flags; - unsigned int consumed; - - local_irq_save(flags); - consumed = ata_sff_data_xfer32(qc, buf, buflen, rw); - local_irq_restore(flags); - - return consumed; -} -EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq); - -/** * ata_pio_sector - Transfer a sector of data. * @qc: Command on going * diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index c47caa807fa9..e3532eda7b05 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -178,7 +178,7 @@ static struct scsi_host_template cmd640_sht = { static struct ata_port_operations cmd640_port_ops = { .inherits = &ata_sff_port_ops, /* In theory xfer_noirq is not needed once we kill the prefetcher */ - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .sff_irq_check = cmd640_sff_irq_check, .qc_issue = cmd640_qc_issue, .cable_detect = ata_cable_40wire, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 188f2f2eb21f..c272f2cbb47c 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -324,7 +324,7 @@ static struct ata_port_operations pata_icside_port_ops = { .inherits = &ata_bmdma_port_ops, /* no need to build any PRD tables for DMA */ .qc_prep = ata_noop_qc_prep, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .bmdma_setup = pata_icside_bmdma_setup, .bmdma_start = pata_icside_bmdma_start, .bmdma_stop = pata_icside_bmdma_stop, diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 6f0534047c6d..2e538726802b 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -103,7 +103,7 @@ static struct scsi_host_template pata_imx_sht = { static struct ata_port_operations pata_imx_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_unknown, .set_piomode = pata_imx_set_piomode, }; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 53828b6c3044..8ea4b8431fc8 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -246,12 +246,12 @@ static const struct ata_port_operations legacy_base_port_ops = { static struct ata_port_operations simple_port_ops = { .inherits = &legacy_base_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, }; static struct ata_port_operations legacy_port_ops = { .inherits = &legacy_base_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .set_mode = legacy_set_mode, }; @@ -341,7 +341,7 @@ static unsigned int pdc_data_xfer_vlb(struct ata_queued_cmd *qc, } local_irq_restore(flags); } else - buflen = ata_sff_data_xfer_noirq(qc, buf, buflen, rw); + buflen = ata_sff_data_xfer32(qc, buf, buflen, rw); return buflen; } diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c index 8c0d7d736b7a..d071ab6864a8 100644 --- a/drivers/ata/pata_palmld.c +++ b/drivers/ata/pata_palmld.c @@ -44,7 +44,7 @@ static struct scsi_host_template palmld_sht = { static struct ata_port_operations palmld_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_40wire, }; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index a541eacc5e95..9b0e6c72e3f9 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -151,7 +151,7 @@ static struct scsi_host_template pcmcia_sht = { static struct ata_port_operations pcmcia_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_40wire, .set_mode = pcmcia_set_mode, }; diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index c503ded87bb8..d6f8f5406442 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -49,7 +49,7 @@ static struct scsi_host_template pata_platform_sht = { static struct ata_port_operations pata_platform_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_unknown, .set_mode = pata_platform_set_mode, }; diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 1ca6bcab369f..fd19f1ce83aa 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -471,7 +471,7 @@ static struct ata_port_operations via_port_ops = { static struct ata_port_operations via_port_ops_noirq = { .inherits = &via_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, }; /** diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 6456e07db72a..10ecb232245d 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -17,7 +17,7 @@ #include <linux/libata.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include <linux/clk.h> +#include <linux/pm_runtime.h> #include <linux/err.h> #define DRV_NAME "sata_rcar" @@ -109,6 +109,8 @@ #define SATAINTMASK_ERRMSK BIT(2) #define SATAINTMASK_ERRCRTMSK BIT(1) #define SATAINTMASK_ATAMSK BIT(0) +#define SATAINTMASK_ALL_GEN1 0x7ff +#define SATAINTMASK_ALL_GEN2 0xfff #define SATA_RCAR_INT_MASK (SATAINTMASK_SERRMSK | \ SATAINTMASK_ATAMSK) @@ -152,7 +154,7 @@ enum sata_rcar_type { struct sata_rcar_priv { void __iomem *base; - struct clk *clk; + u32 sataint_mask; enum sata_rcar_type type; }; @@ -226,7 +228,7 @@ static void sata_rcar_freeze(struct ata_port *ap) struct sata_rcar_priv *priv = ap->host->private_data; /* mask */ - iowrite32(0x7ff, priv->base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, priv->base + SATAINTMASK_REG); ata_sff_freeze(ap); } @@ -242,7 +244,7 @@ static void sata_rcar_thaw(struct ata_port *ap) ata_sff_thaw(ap); /* unmask */ - iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask & ~SATA_RCAR_INT_MASK, base + SATAINTMASK_REG); } static void sata_rcar_ioread16_rep(void __iomem *reg, void *buffer, int count) @@ -736,7 +738,7 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance) if (!sataintstat) goto done; /* ack */ - iowrite32(~sataintstat & 0x7ff, base + SATAINTSTAT_REG); + iowrite32(~sataintstat & priv->sataint_mask, base + SATAINTSTAT_REG); ap = host->ports[0]; @@ -809,7 +811,7 @@ static void sata_rcar_init_module(struct sata_rcar_priv *priv) /* ack and mask */ iowrite32(0, base + SATAINTSTAT_REG); - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); /* enable interrupts */ iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG); @@ -819,16 +821,20 @@ static void sata_rcar_init_controller(struct ata_host *host) { struct sata_rcar_priv *priv = host->private_data; + priv->sataint_mask = SATAINTMASK_ALL_GEN2; + /* reset and setup phy */ switch (priv->type) { case RCAR_GEN1_SATA: + priv->sataint_mask = SATAINTMASK_ALL_GEN1; sata_rcar_gen1_phy_init(priv); break; case RCAR_GEN2_SATA: - case RCAR_GEN3_SATA: case RCAR_R8A7790_ES1_SATA: sata_rcar_gen2_phy_init(priv); break; + case RCAR_GEN3_SATA: + break; default: dev_warn(host->dev, "SATA phy is not initialized\n"); break; @@ -881,6 +887,7 @@ MODULE_DEVICE_TABLE(of, sata_rcar_match); static int sata_rcar_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct ata_host *host; struct sata_rcar_priv *priv; struct resource *mem; @@ -891,36 +898,31 @@ static int sata_rcar_probe(struct platform_device *pdev) if (irq <= 0) return -EINVAL; - priv = devm_kzalloc(&pdev->dev, sizeof(struct sata_rcar_priv), - GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(struct sata_rcar_priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->type = (enum sata_rcar_type)of_device_get_match_data(&pdev->dev); - priv->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "failed to get access to sata clock\n"); - return PTR_ERR(priv->clk); - } + priv->type = (enum sata_rcar_type)of_device_get_match_data(dev); - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto err_pm_disable; - host = ata_host_alloc(&pdev->dev, 1); + host = ata_host_alloc(dev, 1); if (!host) { - dev_err(&pdev->dev, "ata_host_alloc failed\n"); + dev_err(dev, "ata_host_alloc failed\n"); ret = -ENOMEM; - goto cleanup; + goto err_pm_put; } host->private_data = priv; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, mem); + priv->base = devm_ioremap_resource(dev, mem); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); - goto cleanup; + goto err_pm_put; } /* setup port */ @@ -934,9 +936,10 @@ static int sata_rcar_probe(struct platform_device *pdev) if (!ret) return 0; -cleanup: - clk_disable_unprepare(priv->clk); - +err_pm_put: + pm_runtime_put(dev); +err_pm_disable: + pm_runtime_disable(dev); return ret; } @@ -952,9 +955,10 @@ static int sata_rcar_remove(struct platform_device *pdev) iowrite32(0, base + ATAPI_INT_ENABLE_REG); /* ack and mask */ iowrite32(0, base + SATAINTSTAT_REG); - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); - clk_disable_unprepare(priv->clk); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } @@ -972,9 +976,9 @@ static int sata_rcar_suspend(struct device *dev) /* disable interrupts */ iowrite32(0, base + ATAPI_INT_ENABLE_REG); /* mask */ - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); - clk_disable_unprepare(priv->clk); + pm_runtime_put(dev); } return ret; @@ -987,17 +991,16 @@ static int sata_rcar_resume(struct device *dev) void __iomem *base = priv->base; int ret; - ret = clk_prepare_enable(priv->clk); - if (ret) + ret = pm_runtime_get_sync(dev); + if (ret < 0) return ret; if (priv->type == RCAR_GEN3_SATA) { - sata_rcar_gen2_phy_init(priv); sata_rcar_init_module(priv); } else { /* ack and mask */ iowrite32(0, base + SATAINTSTAT_REG); - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); /* enable interrupts */ iowrite32(ATAPI_INT_ENABLE_SATAINT, @@ -1012,11 +1015,10 @@ static int sata_rcar_resume(struct device *dev) static int sata_rcar_restore(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); - struct sata_rcar_priv *priv = host->private_data; int ret; - ret = clk_prepare_enable(priv->clk); - if (ret) + ret = pm_runtime_get_sync(dev); + if (ret < 0) return ret; sata_rcar_setup_port(host); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index f99e5c883368..581312ac375f 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2428,16 +2428,20 @@ static bool DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T { DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; - unsigned char *ReadCacheStatus[] = { "Read Cache Disabled", - "Read Cache Enabled", - "Read Ahead Enabled", - "Intelligent Read Ahead Enabled", - "-", "-", "-", "-" }; - unsigned char *WriteCacheStatus[] = { "Write Cache Disabled", - "Logical Device Read Only", - "Write Cache Enabled", - "Intelligent Write Cache Enabled", - "-", "-", "-", "-" }; + static const unsigned char *ReadCacheStatus[] = { + "Read Cache Disabled", + "Read Cache Enabled", + "Read Ahead Enabled", + "Intelligent Read Ahead Enabled", + "-", "-", "-", "-" + }; + static const unsigned char *WriteCacheStatus[] = { + "Write Cache Disabled", + "Logical Device Read Only", + "Write Cache Enabled", + "Intelligent Write Cache Enabled", + "-", "-", "-", "-" + }; unsigned char *GeometryTranslation; if (LogicalDeviceInfo == NULL) continue; switch (LogicalDeviceInfo->DriveGeometry) @@ -4339,14 +4343,16 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command) static void DAC960_V2_ReadWriteError(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; - unsigned char *SenseErrors[] = { "NO SENSE", "RECOVERED ERROR", - "NOT READY", "MEDIUM ERROR", - "HARDWARE ERROR", "ILLEGAL REQUEST", - "UNIT ATTENTION", "DATA PROTECT", - "BLANK CHECK", "VENDOR-SPECIFIC", - "COPY ABORTED", "ABORTED COMMAND", - "EQUAL", "VOLUME OVERFLOW", - "MISCOMPARE", "RESERVED" }; + static const unsigned char *SenseErrors[] = { + "NO SENSE", "RECOVERED ERROR", + "NOT READY", "MEDIUM ERROR", + "HARDWARE ERROR", "ILLEGAL REQUEST", + "UNIT ATTENTION", "DATA PROTECT", + "BLANK CHECK", "VENDOR-SPECIFIC", + "COPY ABORTED", "ABORTED COMMAND", + "EQUAL", "VOLUME OVERFLOW", + "MISCOMPARE", "RESERVED" + }; unsigned char *CommandName = "UNKNOWN"; switch (Command->CommandType) { diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index db253cd5b32a..d0666f5ce003 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -118,7 +118,6 @@ static struct dentry *dfs_device_status; static u32 cpu_use[NR_CPUS]; -static DEFINE_SPINLOCK(rssd_index_lock); static DEFINE_IDA(rssd_index_ida); static int mtip_block_initialize(struct driver_data *dd); @@ -3767,20 +3766,10 @@ static int mtip_block_initialize(struct driver_data *dd) goto alloc_disk_error; } - /* Generate the disk name, implemented same as in sd.c */ - do { - if (!ida_pre_get(&rssd_index_ida, GFP_KERNEL)) { - rv = -ENOMEM; - goto ida_get_error; - } - - spin_lock(&rssd_index_lock); - rv = ida_get_new(&rssd_index_ida, &index); - spin_unlock(&rssd_index_lock); - } while (rv == -EAGAIN); - - if (rv) + rv = ida_alloc(&rssd_index_ida, GFP_KERNEL); + if (rv < 0) goto ida_get_error; + index = rv; rv = rssd_disk_name_format("rssd", index, @@ -3922,9 +3911,7 @@ block_queue_alloc_init_error: block_queue_alloc_tag_error: mtip_hw_debugfs_exit(dd); disk_index_error: - spin_lock(&rssd_index_lock); - ida_remove(&rssd_index_ida, index); - spin_unlock(&rssd_index_lock); + ida_free(&rssd_index_ida, index); ida_get_error: put_disk(dd->disk); @@ -4012,9 +3999,7 @@ static int mtip_block_remove(struct driver_data *dd) } dd->disk = NULL; - spin_lock(&rssd_index_lock); - ida_remove(&rssd_index_ida, dd->index); - spin_unlock(&rssd_index_lock); + ida_free(&rssd_index_ida, dd->index); /* De-initialize the protocol layer. */ mtip_hw_exit(dd); @@ -4054,9 +4039,7 @@ static int mtip_block_shutdown(struct driver_data *dd) dd->queue = NULL; } - spin_lock(&rssd_index_lock); - ida_remove(&rssd_index_ida, dd->index); - spin_unlock(&rssd_index_lock); + ida_free(&rssd_index_ida, dd->index); return 0; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index e285413d4a75..6f1d25c1eb64 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2740,6 +2740,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) pd->write_congestion_on = write_congestion_on; pd->write_congestion_off = write_congestion_off; + ret = -ENOMEM; disk = alloc_disk(1); if (!disk) goto out_mem; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d81c653b9bf6..7915f3b03736 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -181,6 +181,7 @@ struct rbd_image_header { struct rbd_spec { u64 pool_id; const char *pool_name; + const char *pool_ns; /* NULL if default, never "" */ const char *image_id; const char *image_name; @@ -735,6 +736,7 @@ enum { Opt_lock_timeout, Opt_last_int, /* int args above */ + Opt_pool_ns, Opt_last_string, /* string args above */ Opt_read_only, @@ -749,6 +751,7 @@ static match_table_t rbd_opts_tokens = { {Opt_queue_depth, "queue_depth=%d"}, {Opt_lock_timeout, "lock_timeout=%d"}, /* int args above */ + {Opt_pool_ns, "_pool_ns=%s"}, /* string args above */ {Opt_read_only, "read_only"}, {Opt_read_only, "ro"}, /* Alternate spelling */ @@ -776,9 +779,14 @@ struct rbd_options { #define RBD_EXCLUSIVE_DEFAULT false #define RBD_TRIM_DEFAULT true +struct parse_rbd_opts_ctx { + struct rbd_spec *spec; + struct rbd_options *opts; +}; + static int parse_rbd_opts_token(char *c, void *private) { - struct rbd_options *rbd_opts = private; + struct parse_rbd_opts_ctx *pctx = private; substring_t argstr[MAX_OPT_ARGS]; int token, intval, ret; @@ -786,7 +794,7 @@ static int parse_rbd_opts_token(char *c, void *private) if (token < Opt_last_int) { ret = match_int(&argstr[0], &intval); if (ret < 0) { - pr_err("bad mount option arg (not int) at '%s'\n", c); + pr_err("bad option arg (not int) at '%s'\n", c); return ret; } dout("got int token %d val %d\n", token, intval); @@ -802,7 +810,7 @@ static int parse_rbd_opts_token(char *c, void *private) pr_err("queue_depth out of range\n"); return -EINVAL; } - rbd_opts->queue_depth = intval; + pctx->opts->queue_depth = intval; break; case Opt_lock_timeout: /* 0 is "wait forever" (i.e. infinite timeout) */ @@ -810,22 +818,28 @@ static int parse_rbd_opts_token(char *c, void *private) pr_err("lock_timeout out of range\n"); return -EINVAL; } - rbd_opts->lock_timeout = msecs_to_jiffies(intval * 1000); + pctx->opts->lock_timeout = msecs_to_jiffies(intval * 1000); + break; + case Opt_pool_ns: + kfree(pctx->spec->pool_ns); + pctx->spec->pool_ns = match_strdup(argstr); + if (!pctx->spec->pool_ns) + return -ENOMEM; break; case Opt_read_only: - rbd_opts->read_only = true; + pctx->opts->read_only = true; break; case Opt_read_write: - rbd_opts->read_only = false; + pctx->opts->read_only = false; break; case Opt_lock_on_read: - rbd_opts->lock_on_read = true; + pctx->opts->lock_on_read = true; break; case Opt_exclusive: - rbd_opts->exclusive = true; + pctx->opts->exclusive = true; break; case Opt_notrim: - rbd_opts->trim = false; + pctx->opts->trim = false; break; default: /* libceph prints "bad option" msg */ @@ -1452,7 +1466,7 @@ static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request) struct ceph_osd_request *osd_req = obj_request->osd_req; osd_req->r_flags = CEPH_OSD_FLAG_WRITE; - ktime_get_real_ts(&osd_req->r_mtime); + ktime_get_real_ts64(&osd_req->r_mtime); osd_req->r_data_offset = obj_request->ex.oe_off; } @@ -1475,7 +1489,13 @@ rbd_osd_req_create(struct rbd_obj_request *obj_req, unsigned int num_ops) req->r_callback = rbd_osd_req_callback; req->r_priv = obj_req; + /* + * Data objects may be stored in a separate pool, but always in + * the same namespace in that pool as the header in its pool. + */ + ceph_oloc_copy(&req->r_base_oloc, &rbd_dev->header_oloc); req->r_base_oloc.pool = rbd_dev->layout.pool_id; + if (ceph_oid_aprintf(&req->r_base_oid, GFP_NOIO, name_format, rbd_dev->header.object_prefix, obj_req->ex.oe_objno)) goto err_req; @@ -4119,6 +4139,14 @@ static ssize_t rbd_pool_id_show(struct device *dev, (unsigned long long) rbd_dev->spec->pool_id); } +static ssize_t rbd_pool_ns_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); + + return sprintf(buf, "%s\n", rbd_dev->spec->pool_ns ?: ""); +} + static ssize_t rbd_name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -4217,6 +4245,7 @@ static DEVICE_ATTR(cluster_fsid, 0444, rbd_cluster_fsid_show, NULL); static DEVICE_ATTR(config_info, 0400, rbd_config_info_show, NULL); static DEVICE_ATTR(pool, 0444, rbd_pool_show, NULL); static DEVICE_ATTR(pool_id, 0444, rbd_pool_id_show, NULL); +static DEVICE_ATTR(pool_ns, 0444, rbd_pool_ns_show, NULL); static DEVICE_ATTR(name, 0444, rbd_name_show, NULL); static DEVICE_ATTR(image_id, 0444, rbd_image_id_show, NULL); static DEVICE_ATTR(refresh, 0200, NULL, rbd_image_refresh); @@ -4235,6 +4264,7 @@ static struct attribute *rbd_attrs[] = { &dev_attr_config_info.attr, &dev_attr_pool.attr, &dev_attr_pool_id.attr, + &dev_attr_pool_ns.attr, &dev_attr_name.attr, &dev_attr_image_id.attr, &dev_attr_current_snap.attr, @@ -4295,6 +4325,7 @@ static void rbd_spec_free(struct kref *kref) struct rbd_spec *spec = container_of(kref, struct rbd_spec, kref); kfree(spec->pool_name); + kfree(spec->pool_ns); kfree(spec->image_id); kfree(spec->image_name); kfree(spec->snap_name); @@ -4353,6 +4384,12 @@ static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc, rbd_dev->header.data_pool_id = CEPH_NOPOOL; ceph_oid_init(&rbd_dev->header_oid); rbd_dev->header_oloc.pool = spec->pool_id; + if (spec->pool_ns) { + WARN_ON(!*spec->pool_ns); + rbd_dev->header_oloc.pool_ns = + ceph_find_or_create_string(spec->pool_ns, + strlen(spec->pool_ns)); + } mutex_init(&rbd_dev->watch_mutex); rbd_dev->watch_state = RBD_WATCH_STATE_UNREGISTERED; @@ -4633,6 +4670,17 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) parent_spec->pool_id = pool_id; parent_spec->image_id = image_id; parent_spec->snap_id = snap_id; + + /* TODO: support cloning across namespaces */ + if (rbd_dev->spec->pool_ns) { + parent_spec->pool_ns = kstrdup(rbd_dev->spec->pool_ns, + GFP_KERNEL); + if (!parent_spec->pool_ns) { + ret = -ENOMEM; + goto out_err; + } + } + rbd_dev->parent_spec = parent_spec; parent_spec = NULL; /* rbd_dev now owns this */ } else { @@ -5146,8 +5194,7 @@ static int rbd_add_parse_args(const char *buf, const char *mon_addrs; char *snap_name; size_t mon_addrs_size; - struct rbd_spec *spec = NULL; - struct rbd_options *rbd_opts = NULL; + struct parse_rbd_opts_ctx pctx = { 0 }; struct ceph_options *copts; int ret; @@ -5171,22 +5218,22 @@ static int rbd_add_parse_args(const char *buf, goto out_err; } - spec = rbd_spec_alloc(); - if (!spec) + pctx.spec = rbd_spec_alloc(); + if (!pctx.spec) goto out_mem; - spec->pool_name = dup_token(&buf, NULL); - if (!spec->pool_name) + pctx.spec->pool_name = dup_token(&buf, NULL); + if (!pctx.spec->pool_name) goto out_mem; - if (!*spec->pool_name) { + if (!*pctx.spec->pool_name) { rbd_warn(NULL, "no pool name provided"); goto out_err; } - spec->image_name = dup_token(&buf, NULL); - if (!spec->image_name) + pctx.spec->image_name = dup_token(&buf, NULL); + if (!pctx.spec->image_name) goto out_mem; - if (!*spec->image_name) { + if (!*pctx.spec->image_name) { rbd_warn(NULL, "no image name provided"); goto out_err; } @@ -5207,24 +5254,24 @@ static int rbd_add_parse_args(const char *buf, if (!snap_name) goto out_mem; *(snap_name + len) = '\0'; - spec->snap_name = snap_name; + pctx.spec->snap_name = snap_name; /* Initialize all rbd options to the defaults */ - rbd_opts = kzalloc(sizeof (*rbd_opts), GFP_KERNEL); - if (!rbd_opts) + pctx.opts = kzalloc(sizeof(*pctx.opts), GFP_KERNEL); + if (!pctx.opts) goto out_mem; - rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; - rbd_opts->queue_depth = RBD_QUEUE_DEPTH_DEFAULT; - rbd_opts->lock_timeout = RBD_LOCK_TIMEOUT_DEFAULT; - rbd_opts->lock_on_read = RBD_LOCK_ON_READ_DEFAULT; - rbd_opts->exclusive = RBD_EXCLUSIVE_DEFAULT; - rbd_opts->trim = RBD_TRIM_DEFAULT; + pctx.opts->read_only = RBD_READ_ONLY_DEFAULT; + pctx.opts->queue_depth = RBD_QUEUE_DEPTH_DEFAULT; + pctx.opts->lock_timeout = RBD_LOCK_TIMEOUT_DEFAULT; + pctx.opts->lock_on_read = RBD_LOCK_ON_READ_DEFAULT; + pctx.opts->exclusive = RBD_EXCLUSIVE_DEFAULT; + pctx.opts->trim = RBD_TRIM_DEFAULT; copts = ceph_parse_options(options, mon_addrs, - mon_addrs + mon_addrs_size - 1, - parse_rbd_opts_token, rbd_opts); + mon_addrs + mon_addrs_size - 1, + parse_rbd_opts_token, &pctx); if (IS_ERR(copts)) { ret = PTR_ERR(copts); goto out_err; @@ -5232,15 +5279,15 @@ static int rbd_add_parse_args(const char *buf, kfree(options); *ceph_opts = copts; - *opts = rbd_opts; - *rbd_spec = spec; + *opts = pctx.opts; + *rbd_spec = pctx.spec; return 0; out_mem: ret = -ENOMEM; out_err: - kfree(rbd_opts); - rbd_spec_put(spec); + kfree(pctx.opts); + rbd_spec_put(pctx.spec); kfree(options); return ret; @@ -5586,8 +5633,10 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) ret = rbd_register_watch(rbd_dev); if (ret) { if (ret == -ENOENT) - pr_info("image %s/%s does not exist\n", + pr_info("image %s/%s%s%s does not exist\n", rbd_dev->spec->pool_name, + rbd_dev->spec->pool_ns ?: "", + rbd_dev->spec->pool_ns ? "/" : "", rbd_dev->spec->image_name); goto err_out_format; } @@ -5609,8 +5658,10 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) ret = rbd_spec_fill_names(rbd_dev); if (ret) { if (ret == -ENOENT) - pr_info("snap %s/%s@%s does not exist\n", + pr_info("snap %s/%s%s%s@%s does not exist\n", rbd_dev->spec->pool_name, + rbd_dev->spec->pool_ns ?: "", + rbd_dev->spec->pool_ns ? "/" : "", rbd_dev->spec->image_name, rbd_dev->spec->snap_name); goto err_out_probe; diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index b7d71914a32a..f2c631ce793c 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -58,7 +58,6 @@ MODULE_PARM_DESC(sync_start, "On by Default: Driver load will not complete " "until the card startup has completed."); static DEFINE_IDA(rsxx_disk_ida); -static DEFINE_SPINLOCK(rsxx_ida_lock); /* --------------------Debugfs Setup ------------------- */ @@ -771,19 +770,10 @@ static int rsxx_pci_probe(struct pci_dev *dev, card->dev = dev; pci_set_drvdata(dev, card); - do { - if (!ida_pre_get(&rsxx_disk_ida, GFP_KERNEL)) { - st = -ENOMEM; - goto failed_ida_get; - } - - spin_lock(&rsxx_ida_lock); - st = ida_get_new(&rsxx_disk_ida, &card->disk_id); - spin_unlock(&rsxx_ida_lock); - } while (st == -EAGAIN); - - if (st) + st = ida_alloc(&rsxx_disk_ida, GFP_KERNEL); + if (st < 0) goto failed_ida_get; + card->disk_id = st; st = pci_enable_device(dev); if (st) @@ -985,9 +975,7 @@ failed_request_regions: failed_dma_mask: pci_disable_device(dev); failed_enable: - spin_lock(&rsxx_ida_lock); - ida_remove(&rsxx_disk_ida, card->disk_id); - spin_unlock(&rsxx_ida_lock); + ida_free(&rsxx_disk_ida, card->disk_id); failed_ida_get: kfree(card); @@ -1050,6 +1038,7 @@ static void rsxx_pci_remove(struct pci_dev *dev) pci_disable_device(dev); pci_release_regions(dev); + ida_free(&rsxx_disk_ida, card->disk_id); kfree(card); } diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index c7acf74253a1..a1d6b5597c17 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -337,6 +337,7 @@ static ssize_t backing_dev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { char *file_name; + size_t sz; struct file *backing_dev = NULL; struct inode *inode; struct address_space *mapping; @@ -357,7 +358,11 @@ static ssize_t backing_dev_store(struct device *dev, goto out; } - strlcpy(file_name, buf, len); + strlcpy(file_name, buf, PATH_MAX); + /* ignore trailing newline */ + sz = strlen(file_name); + if (sz > 0 && file_name[sz - 1] == '\n') + file_name[sz - 1] = 0x00; backing_dev = filp_open(file_name, O_RDWR|O_LARGEFILE, 0); if (IS_ERR(backing_dev)) { diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 2df11cc08a46..845b0314ce3a 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -200,6 +200,7 @@ config BT_HCIUART_RTL depends on BT_HCIUART depends on BT_HCIUART_SERDEV depends on GPIOLIB + depends on ACPI select BT_HCIUART_3WIRE select BT_RTL help diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index ed2a5c7cb77f..4593baff2bc9 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -144,8 +144,10 @@ static int mtk_setup_fw(struct hci_dev *hdev) fw_size = fw->size; /* The size of patch header is 30 bytes, should be skip */ - if (fw_size < 30) - return -EINVAL; + if (fw_size < 30) { + err = -EINVAL; + goto free_fw; + } fw_size -= 30; fw_ptr += 30; @@ -172,8 +174,8 @@ static int mtk_setup_fw(struct hci_dev *hdev) fw_ptr += dlen; } +free_fw: release_firmware(fw); - return err; } diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index d1c0b60e9326..1851112ccc29 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -103,6 +103,16 @@ config SIMPLE_PM_BUS Controller (BSC, sometimes called "LBSC within Bus Bridge", or "External Bus Interface") as found on several Renesas ARM SoCs. +config SUN50I_DE2_BUS + bool "Allwinner A64 DE2 Bus Driver" + default ARM64 + depends on ARCH_SUNXI + select SUNXI_SRAM + help + Say y here to enable support for Allwinner A64 DE2 bus driver. It's + mostly transparent, but a SRAM region needs to be claimed in the SRAM + controller to make the all blocks in the DE2 part accessible. + config SUNXI_RSB tristate "Allwinner sunXi Reduced Serial Bus Driver" default MACH_SUN8I || MACH_SUN9I || ARM64 diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index b8f036cca7ff..ca300b1914ce 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o +obj-$(CONFIG_SUN50I_DE2_BUS) += sun50i-de2.o obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o diff --git a/drivers/bus/sun50i-de2.c b/drivers/bus/sun50i-de2.c new file mode 100644 index 000000000000..672518741f86 --- /dev/null +++ b/drivers/bus/sun50i-de2.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner A64 Display Engine 2.0 Bus Driver + * + * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io> + */ + +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/soc/sunxi/sunxi_sram.h> + +static int sun50i_de2_bus_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + ret = sunxi_sram_claim(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Error couldn't map SRAM to device\n"); + return ret; + } + + of_platform_populate(np, NULL, NULL, &pdev->dev); + + return 0; +} + +static int sun50i_de2_bus_remove(struct platform_device *pdev) +{ + sunxi_sram_release(&pdev->dev); + return 0; +} + +static const struct of_device_id sun50i_de2_bus_of_match[] = { + { .compatible = "allwinner,sun50i-a64-de2", }, + { /* sentinel */ } +}; + +static struct platform_driver sun50i_de2_bus_driver = { + .probe = sun50i_de2_bus_probe, + .remove = sun50i_de2_bus_remove, + .driver = { + .name = "sun50i-de2-bus", + .of_match_table = sun50i_de2_bus_of_match, + }, +}; + +builtin_platform_driver(sun50i_de2_bus_driver); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 80d60f43db56..c9bac9dc4637 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -23,11 +23,14 @@ #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/slab.h> +#include <linux/iopoll.h> #include <linux/platform_data/ti-sysc.h> #include <dt-bindings/bus/ti-sysc.h> +#define MAX_MODULE_SOFTRESET_WAIT 10000 + static const char * const reg_names[] = { "rev", "sysc", "syss", }; enum sysc_clocks { @@ -88,6 +91,11 @@ struct sysc { struct delayed_work idle_work; }; +void sysc_write(struct sysc *ddata, int offset, u32 value) +{ + writel_relaxed(value, ddata->module_va + offset); +} + static u32 sysc_read(struct sysc *ddata, int offset) { if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) { @@ -943,6 +951,36 @@ static void sysc_init_revision_quirks(struct sysc *ddata) } } +static int sysc_reset(struct sysc *ddata) +{ + int offset = ddata->offsets[SYSC_SYSCONFIG]; + int val; + + if (ddata->legacy_mode || offset < 0 || + ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) + return 0; + + /* + * Currently only support reset status in sysstatus. + * Warn and return error in all other cases + */ + if (!ddata->cfg.syss_mask) { + dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n"); + return -EINVAL; + } + + val = sysc_read(ddata, offset); + val |= (0x1 << ddata->cap->regbits->srst_shift); + sysc_write(ddata, offset, val); + + /* Poll on reset status */ + offset = ddata->offsets[SYSC_SYSSTATUS]; + + return readl_poll_timeout(ddata->module_va + offset, val, + (val & ddata->cfg.syss_mask) == 0x0, + 100, MAX_MODULE_SOFTRESET_WAIT); +} + /* At this point the module is configured enough to read the revision */ static int sysc_init_module(struct sysc *ddata) { @@ -960,6 +998,14 @@ static int sysc_init_module(struct sysc *ddata) return 0; } + error = sysc_reset(ddata); + if (error) { + dev_err(ddata->dev, "Reset failed with %d\n", error); + pm_runtime_put_sync(ddata->dev); + + return error; + } + ddata->revision = sysc_read_revision(ddata); pm_runtime_put_sync(ddata->dev); @@ -1552,6 +1598,23 @@ static const struct sysc_capabilities sysc_omap4_usb_host_fs = { .regbits = &sysc_regbits_omap4_usb_host_fs, }; +static const struct sysc_regbits sysc_regbits_dra7_mcan = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = -ENODEV, + .clkact_shift = -ENODEV, + .enwkup_shift = 4, + .srst_shift = 0, + .emufree_shift = -ENODEV, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_dra7_mcan = { + .type = TI_SYSC_DRA7_MCAN, + .sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET, + .regbits = &sysc_regbits_dra7_mcan, +}; + static int sysc_init_pdata(struct sysc *ddata) { struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); @@ -1743,6 +1806,7 @@ static const struct of_device_id sysc_match[] = { { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, { .compatible = "ti,sysc-usb-host-fs", .data = &sysc_omap4_usb_host_fs, }, + { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, { }, }; MODULE_DEVICE_TABLE(of, sysc_match); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 94fedeeec035..4948c8bda6b1 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -193,14 +193,6 @@ static unsigned long rtc_freq; /* Current periodic IRQ rate */ static unsigned long rtc_irq_data; /* our output to the world */ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ -#ifdef RTC_IRQ -/* - * rtc_task_lock nests inside rtc_lock. - */ -static DEFINE_SPINLOCK(rtc_task_lock); -static rtc_task_t *rtc_callback; -#endif - /* * If this driver ever becomes modularised, it will be really nice * to make the epoch retain its value across module reload... @@ -264,11 +256,6 @@ static irqreturn_t rtc_interrupt(int irq, void *dev_id) spin_unlock(&rtc_lock); - /* Now do the rest of the actions */ - spin_lock(&rtc_task_lock); - if (rtc_callback) - rtc_callback->func(rtc_callback->private_data); - spin_unlock(&rtc_task_lock); wake_up_interruptible(&rtc_wait); kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); diff --git a/drivers/clk/davinci/psc-da830.c b/drivers/clk/davinci/psc-da830.c index 081b039fcb02..6481337382a6 100644 --- a/drivers/clk/davinci/psc-da830.c +++ b/drivers/clk/davinci/psc-da830.c @@ -14,6 +14,7 @@ #include "psc.h" +LPSC_CLKDEV1(aemif_clkdev, NULL, "ti-aemif"); LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); LPSC_CLKDEV1(mmcsd_clkdev, NULL, "da830-mmc.0"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); @@ -22,7 +23,7 @@ static const struct davinci_lpsc_clk_info da830_psc0_info[] = { LPSC(0, 0, tpcc, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), LPSC(1, 0, tptc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), LPSC(2, 0, tptc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), - LPSC(3, 0, aemif, pll0_sysclk3, NULL, LPSC_ALWAYS_ENABLED), + LPSC(3, 0, aemif, pll0_sysclk3, aemif_clkdev, LPSC_ALWAYS_ENABLED), LPSC(4, 0, spi0, pll0_sysclk2, spi0_clkdev, 0), LPSC(5, 0, mmcsd, pll0_sysclk2, mmcsd_clkdev, 0), LPSC(6, 0, aintc, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED), diff --git a/drivers/clk/davinci/psc-da850.c b/drivers/clk/davinci/psc-da850.c index d196dcbed560..5a18bca464cd 100644 --- a/drivers/clk/davinci/psc-da850.c +++ b/drivers/clk/davinci/psc-da850.c @@ -16,8 +16,7 @@ #include "psc.h" -LPSC_CLKDEV2(emifa_clkdev, NULL, "ti-aemif", - "aemif", "davinci_nand.0"); +LPSC_CLKDEV1(emifa_clkdev, NULL, "ti-aemif"); LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); diff --git a/drivers/clk/davinci/psc-dm365.c b/drivers/clk/davinci/psc-dm365.c index 8c73086cc676..c75424f4ea3b 100644 --- a/drivers/clk/davinci/psc-dm365.c +++ b/drivers/clk/davinci/psc-dm365.c @@ -21,7 +21,8 @@ LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1"); LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp"); LPSC_CLKDEV1(usb_clkdev, "usb", NULL); LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2"); -LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL, + NULL, "ti-aemif"); LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0"); LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); diff --git a/drivers/clk/davinci/psc-dm644x.c b/drivers/clk/davinci/psc-dm644x.c index fc0230e3a3d6..0cea6e0bd5f0 100644 --- a/drivers/clk/davinci/psc-dm644x.c +++ b/drivers/clk/davinci/psc-dm644x.c @@ -21,7 +21,8 @@ LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", "fck", "davinci_mdio.0"); LPSC_CLKDEV1(usb_clkdev, "usb", NULL); LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710"); -LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL, + NULL, "ti-aemif"); LPSC_CLKDEV1(mmcsd_clkdev, NULL, "dm6441-mmc.0"); LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp"); LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); diff --git a/drivers/clk/davinci/psc-dm646x.c b/drivers/clk/davinci/psc-dm646x.c index c3f82ed70a80..20012dc7471a 100644 --- a/drivers/clk/davinci/psc-dm646x.c +++ b/drivers/clk/davinci/psc-dm646x.c @@ -18,7 +18,8 @@ LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710"); LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", "fck", "davinci_mdio.0"); -LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL, + NULL, "ti-aemif"); LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0"); LPSC_CLKDEV1(mcasp1_clkdev, NULL, "davinci-mcasp.1"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 513826393158..1a4e6b787978 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o -obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c deleted file mode 100644 index b08bd54c5e76..000000000000 --- a/drivers/clk/samsung/clk-exynos5440.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * Author: Thomas Abraham <thomas.ab@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Common Clock Framework support for Exynos5440 SoC. -*/ - -#include <dt-bindings/clock/exynos5440.h> -#include <linux/clk-provider.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/notifier.h> -#include <linux/reboot.h> - -#include "clk.h" -#include "clk-pll.h" - -#define CLKEN_OV_VAL 0xf8 -#define CPU_CLK_STATUS 0xfc -#define MISC_DOUT1 0x558 - -static void __iomem *reg_base; - -/* parent clock name list */ -PNAME(mout_armclk_p) = { "cplla", "cpllb" }; -PNAME(mout_spi_p) = { "div125", "div200" }; - -/* fixed rate clocks generated outside the soc */ -static struct samsung_fixed_rate_clock exynos5440_fixed_rate_ext_clks[] __initdata = { - FRATE(0, "xtal", NULL, 0, 0), -}; - -/* fixed rate clocks */ -static const struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initconst = { - FRATE(0, "ppll", NULL, 0, 1000000000), - FRATE(0, "usb_phy0", NULL, 0, 60000000), - FRATE(0, "usb_phy1", NULL, 0, 60000000), - FRATE(0, "usb_ohci12", NULL, 0, 12000000), - FRATE(0, "usb_ohci48", NULL, 0, 48000000), -}; - -/* fixed factor clocks */ -static const struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __initconst = { - FFACTOR(0, "div250", "ppll", 1, 4, 0), - FFACTOR(0, "div200", "ppll", 1, 5, 0), - FFACTOR(0, "div125", "div250", 1, 2, 0), -}; - -/* mux clocks */ -static const struct samsung_mux_clock exynos5440_mux_clks[] __initconst = { - MUX(0, "mout_spi", mout_spi_p, MISC_DOUT1, 5, 1), - MUX(CLK_ARM_CLK, "arm_clk", mout_armclk_p, CPU_CLK_STATUS, 0, 1), -}; - -/* divider clocks */ -static const struct samsung_div_clock exynos5440_div_clks[] __initconst = { - DIV(CLK_SPI_BAUD, "div_spi", "mout_spi", MISC_DOUT1, 3, 2), -}; - -/* gate clocks */ -static const struct samsung_gate_clock exynos5440_gate_clks[] __initconst = { - GATE(CLK_PB0_250, "pb0_250", "div250", CLKEN_OV_VAL, 3, 0, 0), - GATE(CLK_PR0_250, "pr0_250", "div250", CLKEN_OV_VAL, 4, 0, 0), - GATE(CLK_PR1_250, "pr1_250", "div250", CLKEN_OV_VAL, 5, 0, 0), - GATE(CLK_B_250, "b_250", "div250", CLKEN_OV_VAL, 9, 0, 0), - GATE(CLK_B_125, "b_125", "div125", CLKEN_OV_VAL, 10, 0, 0), - GATE(CLK_B_200, "b_200", "div200", CLKEN_OV_VAL, 11, 0, 0), - GATE(CLK_SATA, "sata", "div200", CLKEN_OV_VAL, 12, 0, 0), - GATE(CLK_USB, "usb", "div200", CLKEN_OV_VAL, 13, 0, 0), - GATE(CLK_GMAC0, "gmac0", "div200", CLKEN_OV_VAL, 14, 0, 0), - GATE(CLK_CS250, "cs250", "div250", CLKEN_OV_VAL, 19, 0, 0), - GATE(CLK_PB0_250_O, "pb0_250_o", "pb0_250", CLKEN_OV_VAL, 3, 0, 0), - GATE(CLK_PR0_250_O, "pr0_250_o", "pr0_250", CLKEN_OV_VAL, 4, 0, 0), - GATE(CLK_PR1_250_O, "pr1_250_o", "pr1_250", CLKEN_OV_VAL, 5, 0, 0), - GATE(CLK_B_250_O, "b_250_o", "b_250", CLKEN_OV_VAL, 9, 0, 0), - GATE(CLK_B_125_O, "b_125_o", "b_125", CLKEN_OV_VAL, 10, 0, 0), - GATE(CLK_B_200_O, "b_200_o", "b_200", CLKEN_OV_VAL, 11, 0, 0), - GATE(CLK_SATA_O, "sata_o", "sata", CLKEN_OV_VAL, 12, 0, 0), - GATE(CLK_USB_O, "usb_o", "usb", CLKEN_OV_VAL, 13, 0, 0), - GATE(CLK_GMAC0_O, "gmac0_o", "gmac", CLKEN_OV_VAL, 14, 0, 0), - GATE(CLK_CS250_O, "cs250_o", "cs250", CLKEN_OV_VAL, 19, 0, 0), -}; - -static const struct of_device_id ext_clk_match[] __initconst = { - { .compatible = "samsung,clock-xtal", .data = (void *)0, }, - {}, -}; - -static int exynos5440_clk_restart_notify(struct notifier_block *this, - unsigned long code, void *unused) -{ - u32 val, status; - - status = readl_relaxed(reg_base + 0xbc); - val = readl_relaxed(reg_base + 0xcc); - val = (val & 0xffff0000) | (status & 0xffff); - writel_relaxed(val, reg_base + 0xcc); - - return NOTIFY_DONE; -} - -/* - * Exynos5440 Clock restart notifier, handles restart functionality - */ -static struct notifier_block exynos5440_clk_restart_handler = { - .notifier_call = exynos5440_clk_restart_notify, - .priority = 128, -}; - -static const struct samsung_pll_clock exynos5440_plls[] __initconst = { - PLL(pll_2550x, CLK_CPLLA, "cplla", "xtal", 0, 0x4c, NULL), - PLL(pll_2550x, CLK_CPLLB, "cpllb", "xtal", 0, 0x50, NULL), -}; - -/* - * Clock aliases for legacy clkdev look-up. - */ -static const struct samsung_clock_alias exynos5440_aliases[] __initconst = { - ALIAS(CLK_ARM_CLK, NULL, "armclk"), -}; - -/* register exynos5440 clocks */ -static void __init exynos5440_clk_init(struct device_node *np) -{ - struct samsung_clk_provider *ctx; - - reg_base = of_iomap(np, 0); - if (!reg_base) { - pr_err("%s: failed to map clock controller registers," - " aborting clock initialization\n", __func__); - return; - } - - ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); - - samsung_clk_of_register_fixed_ext(ctx, exynos5440_fixed_rate_ext_clks, - ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match); - - samsung_clk_register_pll(ctx, exynos5440_plls, - ARRAY_SIZE(exynos5440_plls), ctx->reg_base); - - samsung_clk_register_fixed_rate(ctx, exynos5440_fixed_rate_clks, - ARRAY_SIZE(exynos5440_fixed_rate_clks)); - samsung_clk_register_fixed_factor(ctx, exynos5440_fixed_factor_clks, - ARRAY_SIZE(exynos5440_fixed_factor_clks)); - samsung_clk_register_mux(ctx, exynos5440_mux_clks, - ARRAY_SIZE(exynos5440_mux_clks)); - samsung_clk_register_div(ctx, exynos5440_div_clks, - ARRAY_SIZE(exynos5440_div_clks)); - samsung_clk_register_gate(ctx, exynos5440_gate_clks, - ARRAY_SIZE(exynos5440_gate_clks)); - samsung_clk_register_alias(ctx, exynos5440_aliases, - ARRAY_SIZE(exynos5440_aliases)); - - samsung_clk_of_add_provider(np, ctx); - - if (register_restart_handler(&exynos5440_clk_restart_handler)) - pr_warn("exynos5440 clock can't register restart handler\n"); - - pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk")); - pr_info("exynos5440 clock initialization complete\n"); -} -CLK_OF_DECLARE(exynos5440_clk, "samsung,exynos5440-clock", exynos5440_clk_init); diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index fb249a1637a5..71a122b2dc67 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -708,6 +708,7 @@ static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initcons { DRA7_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, { DRA7_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0060:24" }, { DRA7_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0068:24" }, + { DRA7_ADC_CLKCTRL, NULL, CLKF_SW_SUP, "mcan_clk"}, { 0 }, }; diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 52f5f1a2040c..0cd8eb76ad59 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -71,20 +71,6 @@ config ARM_BRCMSTB_AVS_CPUFREQ Say Y, if you have a Broadcom SoC with AVS support for DFS or DVFS. -config ARM_EXYNOS5440_CPUFREQ - tristate "SAMSUNG EXYNOS5440" - depends on SOC_EXYNOS5440 - depends on HAVE_CLK && OF - select PM_OPP - default y - help - This adds the CPUFreq driver for Samsung EXYNOS5440 - SoC. The nature of exynos5440 clock controller is - different than previous exynos controllers so not using - the common exynos framework. - - If in doubt, say N. - config ARM_HIGHBANK_CPUFREQ tristate "Calxeda Highbank-based" depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index fb4a2ecac43b..c1ffeabe4ecf 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -56,7 +56,6 @@ obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o -obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 1d50e97d49f1..6d53f7d9fc7a 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -555,12 +555,20 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop); void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) { - struct policy_dbs_info *policy_dbs = policy->governor_data; + struct policy_dbs_info *policy_dbs; + + /* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */ + mutex_lock(&gov_dbs_data_mutex); + policy_dbs = policy->governor_data; + if (!policy_dbs) + goto out; mutex_lock(&policy_dbs->update_mutex); cpufreq_policy_apply_limits(policy); gov_update_sample_delay(policy_dbs, 0); - mutex_unlock(&policy_dbs->update_mutex); + +out: + mutex_unlock(&gov_dbs_data_mutex); } EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits); diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c deleted file mode 100644 index 932caa386ece..000000000000 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Amit Daniel Kachhap <amit.daniel@samsung.com> - * - * EXYNOS5440 - CPU frequency scaling support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/clk.h> -#include <linux/cpu.h> -#include <linux/cpufreq.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/pm_opp.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -/* Register definitions */ -#define XMU_DVFS_CTRL 0x0060 -#define XMU_PMU_P0_7 0x0064 -#define XMU_C0_3_PSTATE 0x0090 -#define XMU_P_LIMIT 0x00a0 -#define XMU_P_STATUS 0x00a4 -#define XMU_PMUEVTEN 0x00d0 -#define XMU_PMUIRQEN 0x00d4 -#define XMU_PMUIRQ 0x00d8 - -/* PMU mask and shift definations */ -#define P_VALUE_MASK 0x7 - -#define XMU_DVFS_CTRL_EN_SHIFT 0 - -#define P0_7_CPUCLKDEV_SHIFT 21 -#define P0_7_CPUCLKDEV_MASK 0x7 -#define P0_7_ATBCLKDEV_SHIFT 18 -#define P0_7_ATBCLKDEV_MASK 0x7 -#define P0_7_CSCLKDEV_SHIFT 15 -#define P0_7_CSCLKDEV_MASK 0x7 -#define P0_7_CPUEMA_SHIFT 28 -#define P0_7_CPUEMA_MASK 0xf -#define P0_7_L2EMA_SHIFT 24 -#define P0_7_L2EMA_MASK 0xf -#define P0_7_VDD_SHIFT 8 -#define P0_7_VDD_MASK 0x7f -#define P0_7_FREQ_SHIFT 0 -#define P0_7_FREQ_MASK 0xff - -#define C0_3_PSTATE_VALID_SHIFT 8 -#define C0_3_PSTATE_CURR_SHIFT 4 -#define C0_3_PSTATE_NEW_SHIFT 0 - -#define PSTATE_CHANGED_EVTEN_SHIFT 0 - -#define PSTATE_CHANGED_IRQEN_SHIFT 0 - -#define PSTATE_CHANGED_SHIFT 0 - -/* some constant values for clock divider calculation */ -#define CPU_DIV_FREQ_MAX 500 -#define CPU_DBG_FREQ_MAX 375 -#define CPU_ATB_FREQ_MAX 500 - -#define PMIC_LOW_VOLT 0x30 -#define PMIC_HIGH_VOLT 0x28 - -#define CPUEMA_HIGH 0x2 -#define CPUEMA_MID 0x4 -#define CPUEMA_LOW 0x7 - -#define L2EMA_HIGH 0x1 -#define L2EMA_MID 0x3 -#define L2EMA_LOW 0x4 - -#define DIV_TAB_MAX 2 -/* frequency unit is 20MHZ */ -#define FREQ_UNIT 20 -#define MAX_VOLTAGE 1550000 /* In microvolt */ -#define VOLTAGE_STEP 12500 /* In microvolt */ - -#define CPUFREQ_NAME "exynos5440_dvfs" -#define DEF_TRANS_LATENCY 100000 - -enum cpufreq_level_index { - L0, L1, L2, L3, L4, - L5, L6, L7, L8, L9, -}; -#define CPUFREQ_LEVEL_END (L7 + 1) - -struct exynos_dvfs_data { - void __iomem *base; - struct resource *mem; - int irq; - struct clk *cpu_clk; - unsigned int latency; - struct cpufreq_frequency_table *freq_table; - unsigned int freq_count; - struct device *dev; - bool dvfs_enabled; - struct work_struct irq_work; -}; - -static struct exynos_dvfs_data *dvfs_info; -static DEFINE_MUTEX(cpufreq_lock); -static struct cpufreq_freqs freqs; - -static int init_div_table(void) -{ - struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table; - unsigned int tmp, clk_div, ema_div, freq, volt_id, idx; - struct dev_pm_opp *opp; - - cpufreq_for_each_entry_idx(pos, freq_tbl, idx) { - opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, - pos->frequency * 1000, true); - if (IS_ERR(opp)) { - dev_err(dvfs_info->dev, - "failed to find valid OPP for %u KHZ\n", - pos->frequency); - return PTR_ERR(opp); - } - - freq = pos->frequency / 1000; /* In MHZ */ - clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK) - << P0_7_CPUCLKDEV_SHIFT; - clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK) - << P0_7_ATBCLKDEV_SHIFT; - clk_div |= ((freq / CPU_DBG_FREQ_MAX) & P0_7_CSCLKDEV_MASK) - << P0_7_CSCLKDEV_SHIFT; - - /* Calculate EMA */ - volt_id = dev_pm_opp_get_voltage(opp); - - volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP; - if (volt_id < PMIC_HIGH_VOLT) { - ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) | - (L2EMA_HIGH << P0_7_L2EMA_SHIFT); - } else if (volt_id > PMIC_LOW_VOLT) { - ema_div = (CPUEMA_LOW << P0_7_CPUEMA_SHIFT) | - (L2EMA_LOW << P0_7_L2EMA_SHIFT); - } else { - ema_div = (CPUEMA_MID << P0_7_CPUEMA_SHIFT) | - (L2EMA_MID << P0_7_L2EMA_SHIFT); - } - - tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT) - | ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT)); - - __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * idx); - dev_pm_opp_put(opp); - } - - return 0; -} - -static void exynos_enable_dvfs(unsigned int cur_frequency) -{ - unsigned int tmp, cpu; - struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; - struct cpufreq_frequency_table *pos; - /* Disable DVFS */ - __raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL); - - /* Enable PSTATE Change Event */ - tmp = __raw_readl(dvfs_info->base + XMU_PMUEVTEN); - tmp |= (1 << PSTATE_CHANGED_EVTEN_SHIFT); - __raw_writel(tmp, dvfs_info->base + XMU_PMUEVTEN); - - /* Enable PSTATE Change IRQ */ - tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQEN); - tmp |= (1 << PSTATE_CHANGED_IRQEN_SHIFT); - __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN); - - /* Set initial performance index */ - cpufreq_for_each_entry(pos, freq_table) - if (pos->frequency == cur_frequency) - break; - - if (pos->frequency == CPUFREQ_TABLE_END) { - dev_crit(dvfs_info->dev, "Boot up frequency not supported\n"); - /* Assign the highest frequency */ - pos = freq_table; - cur_frequency = pos->frequency; - } - - dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ", - cur_frequency); - - for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) { - tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); - tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT); - tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT); - __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); - } - - /* Enable DVFS */ - __raw_writel(1 << XMU_DVFS_CTRL_EN_SHIFT, - dvfs_info->base + XMU_DVFS_CTRL); -} - -static int exynos_target(struct cpufreq_policy *policy, unsigned int index) -{ - unsigned int tmp; - int i; - struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; - - mutex_lock(&cpufreq_lock); - - freqs.old = policy->cur; - freqs.new = freq_table[index].frequency; - - cpufreq_freq_transition_begin(policy, &freqs); - - /* Set the target frequency in all C0_3_PSTATE register */ - for_each_cpu(i, policy->cpus) { - tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + i * 4); - tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT); - tmp |= (index << C0_3_PSTATE_NEW_SHIFT); - - __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + i * 4); - } - mutex_unlock(&cpufreq_lock); - return 0; -} - -static void exynos_cpufreq_work(struct work_struct *work) -{ - unsigned int cur_pstate, index; - struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */ - struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; - - /* Ensure we can access cpufreq structures */ - if (unlikely(dvfs_info->dvfs_enabled == false)) - goto skip_work; - - mutex_lock(&cpufreq_lock); - freqs.old = policy->cur; - - cur_pstate = __raw_readl(dvfs_info->base + XMU_P_STATUS); - if (cur_pstate >> C0_3_PSTATE_VALID_SHIFT & 0x1) - index = (cur_pstate >> C0_3_PSTATE_CURR_SHIFT) & P_VALUE_MASK; - else - index = (cur_pstate >> C0_3_PSTATE_NEW_SHIFT) & P_VALUE_MASK; - - if (likely(index < dvfs_info->freq_count)) { - freqs.new = freq_table[index].frequency; - } else { - dev_crit(dvfs_info->dev, "New frequency out of range\n"); - freqs.new = freqs.old; - } - cpufreq_freq_transition_end(policy, &freqs, 0); - - cpufreq_cpu_put(policy); - mutex_unlock(&cpufreq_lock); -skip_work: - enable_irq(dvfs_info->irq); -} - -static irqreturn_t exynos_cpufreq_irq(int irq, void *id) -{ - unsigned int tmp; - - tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQ); - if (tmp >> PSTATE_CHANGED_SHIFT & 0x1) { - __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQ); - disable_irq_nosync(irq); - schedule_work(&dvfs_info->irq_work); - } - return IRQ_HANDLED; -} - -static void exynos_sort_descend_freq_table(void) -{ - struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table; - int i = 0, index; - unsigned int tmp_freq; - /* - * Exynos5440 clock controller state logic expects the cpufreq table to - * be in descending order. But the OPP library constructs the table in - * ascending order. So to make the table descending we just need to - * swap the i element with the N - i element. - */ - for (i = 0; i < dvfs_info->freq_count / 2; i++) { - index = dvfs_info->freq_count - i - 1; - tmp_freq = freq_tbl[i].frequency; - freq_tbl[i].frequency = freq_tbl[index].frequency; - freq_tbl[index].frequency = tmp_freq; - } -} - -static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) -{ - policy->clk = dvfs_info->cpu_clk; - return cpufreq_generic_init(policy, dvfs_info->freq_table, - dvfs_info->latency); -} - -static struct cpufreq_driver exynos_driver = { - .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION | - CPUFREQ_NEED_INITIAL_FREQ_CHECK, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = exynos_target, - .get = cpufreq_generic_get, - .init = exynos_cpufreq_cpu_init, - .name = CPUFREQ_NAME, - .attr = cpufreq_generic_attr, -}; - -static const struct of_device_id exynos_cpufreq_match[] = { - { - .compatible = "samsung,exynos5440-cpufreq", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, exynos_cpufreq_match); - -static int exynos_cpufreq_probe(struct platform_device *pdev) -{ - int ret = -EINVAL; - struct device_node *np; - struct resource res; - unsigned int cur_frequency; - - np = pdev->dev.of_node; - if (!np) - return -ENODEV; - - dvfs_info = devm_kzalloc(&pdev->dev, sizeof(*dvfs_info), GFP_KERNEL); - if (!dvfs_info) { - ret = -ENOMEM; - goto err_put_node; - } - - dvfs_info->dev = &pdev->dev; - - ret = of_address_to_resource(np, 0, &res); - if (ret) - goto err_put_node; - - dvfs_info->base = devm_ioremap_resource(dvfs_info->dev, &res); - if (IS_ERR(dvfs_info->base)) { - ret = PTR_ERR(dvfs_info->base); - goto err_put_node; - } - - dvfs_info->irq = irq_of_parse_and_map(np, 0); - if (!dvfs_info->irq) { - dev_err(dvfs_info->dev, "No cpufreq irq found\n"); - ret = -ENODEV; - goto err_put_node; - } - - ret = dev_pm_opp_of_add_table(dvfs_info->dev); - if (ret) { - dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret); - goto err_put_node; - } - - ret = dev_pm_opp_init_cpufreq_table(dvfs_info->dev, - &dvfs_info->freq_table); - if (ret) { - dev_err(dvfs_info->dev, - "failed to init cpufreq table: %d\n", ret); - goto err_free_opp; - } - dvfs_info->freq_count = dev_pm_opp_get_opp_count(dvfs_info->dev); - exynos_sort_descend_freq_table(); - - if (of_property_read_u32(np, "clock-latency", &dvfs_info->latency)) - dvfs_info->latency = DEF_TRANS_LATENCY; - - dvfs_info->cpu_clk = devm_clk_get(dvfs_info->dev, "armclk"); - if (IS_ERR(dvfs_info->cpu_clk)) { - dev_err(dvfs_info->dev, "Failed to get cpu clock\n"); - ret = PTR_ERR(dvfs_info->cpu_clk); - goto err_free_table; - } - - cur_frequency = clk_get_rate(dvfs_info->cpu_clk); - if (!cur_frequency) { - dev_err(dvfs_info->dev, "Failed to get clock rate\n"); - ret = -EINVAL; - goto err_free_table; - } - cur_frequency /= 1000; - - INIT_WORK(&dvfs_info->irq_work, exynos_cpufreq_work); - ret = devm_request_irq(dvfs_info->dev, dvfs_info->irq, - exynos_cpufreq_irq, IRQF_TRIGGER_NONE, - CPUFREQ_NAME, dvfs_info); - if (ret) { - dev_err(dvfs_info->dev, "Failed to register IRQ\n"); - goto err_free_table; - } - - ret = init_div_table(); - if (ret) { - dev_err(dvfs_info->dev, "Failed to initialise div table\n"); - goto err_free_table; - } - - exynos_enable_dvfs(cur_frequency); - ret = cpufreq_register_driver(&exynos_driver); - if (ret) { - dev_err(dvfs_info->dev, - "%s: failed to register cpufreq driver\n", __func__); - goto err_free_table; - } - - of_node_put(np); - dvfs_info->dvfs_enabled = true; - return 0; - -err_free_table: - dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); -err_free_opp: - dev_pm_opp_of_remove_table(dvfs_info->dev); -err_put_node: - of_node_put(np); - dev_err(&pdev->dev, "%s: failed initialization\n", __func__); - return ret; -} - -static int exynos_cpufreq_remove(struct platform_device *pdev) -{ - cpufreq_unregister_driver(&exynos_driver); - dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); - dev_pm_opp_of_remove_table(dvfs_info->dev); - return 0; -} - -static struct platform_driver exynos_cpufreq_platdrv = { - .driver = { - .name = "exynos5440-cpufreq", - .of_match_table = exynos_cpufreq_match, - }, - .probe = exynos_cpufreq_probe, - .remove = exynos_cpufreq_remove, -}; -module_platform_driver(exynos_cpufreq_platdrv); - -MODULE_AUTHOR("Amit Daniel Kachhap <amit.daniel@samsung.com>"); -MODULE_DESCRIPTION("Exynos5440 cpufreq driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 1aef60d160eb..110483f0e3fb 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -328,9 +328,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, unsigned int polling_threshold; /* - * We want to default to C1 (hlt), not to busy polling - * unless the timer is happening really really soon, or - * C1's exit latency exceeds the user configured limit. + * Default to a physical idle state, not to busy polling, unless + * a timer is going to trigger really really soon. */ polling_threshold = max_t(unsigned int, 20, s->target_residency); if (data->next_timer_us > polling_threshold && @@ -349,14 +348,12 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * If the tick is already stopped, the cost of possible short * idle duration misprediction is much higher, because the CPU * may be stuck in a shallow idle state for a long time as a - * result of it. In that case say we might mispredict and try - * to force the CPU into a state for which we would have stopped - * the tick, unless a timer is going to expire really soon - * anyway. + * result of it. In that case say we might mispredict and use + * the known time till the closest timer event for the idle + * state selection. */ if (data->predicted_us < TICK_USEC) - data->predicted_us = min_t(unsigned int, TICK_USEC, - ktime_to_us(delta_next)); + data->predicted_us = ktime_to_us(delta_next); } else { /* * Use the performance multiplier and the user-configurable @@ -381,8 +378,22 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, continue; if (idx == -1) idx = i; /* first enabled state */ - if (s->target_residency > data->predicted_us) - break; + if (s->target_residency > data->predicted_us) { + if (!tick_nohz_tick_stopped()) + break; + + /* + * If the state selected so far is shallow and this + * state's target residency matches the time till the + * closest timer event, select this one to avoid getting + * stuck in the shallow one for too long. + */ + if (drv->states[idx].target_residency < TICK_USEC && + s->target_residency <= ktime_to_us(delta_next)) + idx = i; + + goto out; + } if (s->exit_latency > latency_req) { /* * If we break out of the loop for latency reasons, use @@ -403,14 +414,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * Don't stop the tick if the selected state is a polling one or if the * expected idle duration is shorter than the tick period length. */ - if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || - expected_interval < TICK_USEC) { + if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || + expected_interval < TICK_USEC) && !tick_nohz_tick_stopped()) { unsigned int delta_next_us = ktime_to_us(delta_next); *stop_tick = false; - if (!tick_nohz_tick_stopped() && idx > 0 && - drv->states[idx].target_residency > delta_next_us) { + if (idx > 0 && drv->states[idx].target_residency > delta_next_us) { /* * The tick is not going to be stopped and the target * residency of the state to be returned is not within @@ -418,8 +428,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * tick, so try to correct that. */ for (i = idx - 1; i >= 0; i--) { - if (drv->states[i].disabled || - dev->states_usage[i].disable) + if (drv->states[i].disabled || + dev->states_usage[i].disable) continue; idx = i; @@ -429,6 +439,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } } +out: data->last_state_idx = idx; return data->last_state_idx; diff --git a/drivers/crypto/caam/sg_sw_qm2.h b/drivers/crypto/caam/sg_sw_qm2.h index 31b440757146..b5b4c12179df 100644 --- a/drivers/crypto/caam/sg_sw_qm2.h +++ b/drivers/crypto/caam/sg_sw_qm2.h @@ -35,7 +35,7 @@ #ifndef _SG_SW_QM2_H_ #define _SG_SW_QM2_H_ -#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-fd.h> static inline void dma_to_qm_sg_one(struct dpaa2_sg_entry *qm_sg_ptr, dma_addr_t dma, u32 len, u16 offset) diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h index e586ffab8358..dbfa9fce33e0 100644 --- a/drivers/crypto/caam/sg_sw_sec4.h +++ b/drivers/crypto/caam/sg_sw_sec4.h @@ -12,7 +12,7 @@ #include "ctrl.h" #include "regs.h" #include "sg_sw_qm2.h" -#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-fd.h> struct sec4_sg_entry { u64 ptr; diff --git a/drivers/crypto/vmx/ghashp8-ppc.pl b/drivers/crypto/vmx/ghashp8-ppc.pl index f746af271460..38b06503ede0 100644 --- a/drivers/crypto/vmx/ghashp8-ppc.pl +++ b/drivers/crypto/vmx/ghashp8-ppc.pl @@ -129,9 +129,9 @@ $code=<<___; le?vperm $IN,$IN,$IN,$lemask vxor $zero,$zero,$zero - vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo - vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi - vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi vpmsumd $t2,$Xl,$xC2 # 1st phase @@ -187,11 +187,11 @@ $code=<<___; .align 5 Loop: subic $len,$len,16 - vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo subfe. r0,r0,r0 # borrow?-1:0 - vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi and r0,r0,$len - vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi add $inp,$inp,r0 vpmsumd $t2,$Xl,$xC2 # 1st phase diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 0a2acd7993f0..6fd46083e629 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -248,13 +248,12 @@ __weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff, return -1; } -static int __dev_dax_pte_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) +static vm_fault_t __dev_dax_pte_fault(struct dev_dax *dev_dax, + struct vm_fault *vmf, pfn_t *pfn) { struct device *dev = &dev_dax->dev; struct dax_region *dax_region; - int rc = VM_FAULT_SIGBUS; phys_addr_t phys; - pfn_t pfn; unsigned int fault_size = PAGE_SIZE; if (check_vma(dev_dax, vmf->vma, __func__)) @@ -276,26 +275,19 @@ static int __dev_dax_pte_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } - pfn = phys_to_pfn_t(phys, dax_region->pfn_flags); - - rc = vm_insert_mixed(vmf->vma, vmf->address, pfn); - - if (rc == -ENOMEM) - return VM_FAULT_OOM; - if (rc < 0 && rc != -EBUSY) - return VM_FAULT_SIGBUS; + *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags); - return VM_FAULT_NOPAGE; + return vmf_insert_mixed(vmf->vma, vmf->address, *pfn); } -static int __dev_dax_pmd_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) +static vm_fault_t __dev_dax_pmd_fault(struct dev_dax *dev_dax, + struct vm_fault *vmf, pfn_t *pfn) { unsigned long pmd_addr = vmf->address & PMD_MASK; struct device *dev = &dev_dax->dev; struct dax_region *dax_region; phys_addr_t phys; pgoff_t pgoff; - pfn_t pfn; unsigned int fault_size = PMD_SIZE; if (check_vma(dev_dax, vmf->vma, __func__)) @@ -331,21 +323,21 @@ static int __dev_dax_pmd_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } - pfn = phys_to_pfn_t(phys, dax_region->pfn_flags); + *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags); - return vmf_insert_pfn_pmd(vmf->vma, vmf->address, vmf->pmd, pfn, + return vmf_insert_pfn_pmd(vmf->vma, vmf->address, vmf->pmd, *pfn, vmf->flags & FAULT_FLAG_WRITE); } #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD -static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) +static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax, + struct vm_fault *vmf, pfn_t *pfn) { unsigned long pud_addr = vmf->address & PUD_MASK; struct device *dev = &dev_dax->dev; struct dax_region *dax_region; phys_addr_t phys; pgoff_t pgoff; - pfn_t pfn; unsigned int fault_size = PUD_SIZE; @@ -382,23 +374,26 @@ static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } - pfn = phys_to_pfn_t(phys, dax_region->pfn_flags); + *pfn = phys_to_pfn_t(phys, dax_region->pfn_flags); - return vmf_insert_pfn_pud(vmf->vma, vmf->address, vmf->pud, pfn, + return vmf_insert_pfn_pud(vmf->vma, vmf->address, vmf->pud, *pfn, vmf->flags & FAULT_FLAG_WRITE); } #else -static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) +static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax, + struct vm_fault *vmf, pfn_t *pfn) { return VM_FAULT_FALLBACK; } #endif /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */ -static int dev_dax_huge_fault(struct vm_fault *vmf, +static vm_fault_t dev_dax_huge_fault(struct vm_fault *vmf, enum page_entry_size pe_size) { - int rc, id; struct file *filp = vmf->vma->vm_file; + unsigned long fault_size; + int rc, id; + pfn_t pfn; struct dev_dax *dev_dax = filp->private_data; dev_dbg(&dev_dax->dev, "%s: %s (%#lx - %#lx) size = %d\n", current->comm, @@ -408,23 +403,49 @@ static int dev_dax_huge_fault(struct vm_fault *vmf, id = dax_read_lock(); switch (pe_size) { case PE_SIZE_PTE: - rc = __dev_dax_pte_fault(dev_dax, vmf); + fault_size = PAGE_SIZE; + rc = __dev_dax_pte_fault(dev_dax, vmf, &pfn); break; case PE_SIZE_PMD: - rc = __dev_dax_pmd_fault(dev_dax, vmf); + fault_size = PMD_SIZE; + rc = __dev_dax_pmd_fault(dev_dax, vmf, &pfn); break; case PE_SIZE_PUD: - rc = __dev_dax_pud_fault(dev_dax, vmf); + fault_size = PUD_SIZE; + rc = __dev_dax_pud_fault(dev_dax, vmf, &pfn); break; default: rc = VM_FAULT_SIGBUS; } + + if (rc == VM_FAULT_NOPAGE) { + unsigned long i; + pgoff_t pgoff; + + /* + * In the device-dax case the only possibility for a + * VM_FAULT_NOPAGE result is when device-dax capacity is + * mapped. No need to consider the zero page, or racing + * conflicting mappings. + */ + pgoff = linear_page_index(vmf->vma, vmf->address + & ~(fault_size - 1)); + for (i = 0; i < fault_size / PAGE_SIZE; i++) { + struct page *page; + + page = pfn_to_page(pfn_t_to_pfn(pfn) + i); + if (page->mapping) + continue; + page->mapping = filp->f_mapping; + page->index = pgoff + i; + } + } dax_read_unlock(id); return rc; } -static int dev_dax_fault(struct vm_fault *vmf) +static vm_fault_t dev_dax_fault(struct vm_fault *vmf) { return dev_dax_huge_fault(vmf, PE_SIZE_PTE); } diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index fd49b24fd6af..99e2aace8078 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -105,15 +105,19 @@ static int dax_pmem_probe(struct device *dev) if (rc) return rc; - rc = devm_add_action_or_reset(dev, dax_pmem_percpu_exit, - &dax_pmem->ref); - if (rc) + rc = devm_add_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref); + if (rc) { + percpu_ref_exit(&dax_pmem->ref); return rc; + } dax_pmem->pgmap.ref = &dax_pmem->ref; addr = devm_memremap_pages(dev, &dax_pmem->pgmap); - if (IS_ERR(addr)) + if (IS_ERR(addr)) { + devm_remove_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref); + percpu_ref_exit(&dax_pmem->ref); return PTR_ERR(addr); + } rc = devm_add_action_or_reset(dev, dax_pmem_percpu_kill, &dax_pmem->ref); diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 45276abf03aa..6e928f37d084 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -89,7 +89,6 @@ bool __bdev_dax_supported(struct block_device *bdev, int blocksize) struct request_queue *q; pgoff_t pgoff; int err, id; - void *kaddr; pfn_t pfn; long len; char buf[BDEVNAME_SIZE]; @@ -122,7 +121,7 @@ bool __bdev_dax_supported(struct block_device *bdev, int blocksize) } id = dax_read_lock(); - len = dax_direct_access(dax_dev, pgoff, 1, &kaddr, &pfn); + len = dax_direct_access(dax_dev, pgoff, 1, NULL, &pfn); dax_read_unlock(id); put_dax(dax_dev); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 272bed6c8ba7..f1a441ab395d 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -161,9 +161,7 @@ static void chan_dev_release(struct device *dev) chan_dev = container_of(dev, typeof(*chan_dev), device); if (atomic_dec_and_test(chan_dev->idr_ref)) { - mutex_lock(&dma_list_mutex); - ida_remove(&dma_ida, chan_dev->dev_id); - mutex_unlock(&dma_list_mutex); + ida_free(&dma_ida, chan_dev->dev_id); kfree(chan_dev->idr_ref); } kfree(chan_dev); @@ -898,17 +896,12 @@ static bool device_has_all_tx_types(struct dma_device *device) static int get_dma_id(struct dma_device *device) { - int rc; - - do { - if (!ida_pre_get(&dma_ida, GFP_KERNEL)) - return -ENOMEM; - mutex_lock(&dma_list_mutex); - rc = ida_get_new(&dma_ida, &device->dev_id); - mutex_unlock(&dma_list_mutex); - } while (rc == -EAGAIN); + int rc = ida_alloc(&dma_ida, GFP_KERNEL); - return rc; + if (rc < 0) + return rc; + device->dev_id = rc; + return 0; } /** @@ -1092,9 +1085,7 @@ int dma_async_device_register(struct dma_device *device) err_out: /* if we never registered a channel just release the idr */ if (atomic_read(idr_ref) == 0) { - mutex_lock(&dma_list_mutex); - ida_remove(&dma_ida, device->dev_id); - mutex_unlock(&dma_list_mutex); + ida_free(&dma_ida, device->dev_id); kfree(idr_ref); return rc; } diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 3bb82e511eca..7d3edd713932 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -215,6 +215,7 @@ const char * const edac_mem_types[] = { [MEM_LRDDR3] = "Load-Reduced-DDR3-RAM", [MEM_DDR4] = "Unbuffered-DDR4", [MEM_RDDR4] = "Registered-DDR4", + [MEM_LRDDR4] = "Load-Reduced-DDR4-RAM", [MEM_NVDIMM] = "Non-volatile-RAM", }; EXPORT_SYMBOL_GPL(edac_mem_types); diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 2a219b1261b1..721e6c57beae 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -363,8 +363,6 @@ static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle, return domain; dom = pi->dom_info + domain; - if (!dom) - return -EIO; for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { freq = opp->perf * dom->mult_factor; @@ -394,9 +392,6 @@ static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle, return domain; dom = pi->dom_info + domain; - if (!dom) - return -EIO; - /* uS to nS */ return dom->opp[dom->opp_count - 1].trans_latency_us * 1000; } diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index 50793fda7819..b22ccfb0c991 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -20,7 +20,7 @@ #include <linux/efi-bgrt.h> struct acpi_table_bgrt bgrt_tab; -size_t __initdata bgrt_image_size; +size_t bgrt_image_size; struct bmp_header { u16 id; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 88c322d7c71e..14c40a7750d1 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -24,6 +24,7 @@ KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \ -D__NO_FORTIFY \ $(call cc-option,-ffreestanding) \ $(call cc-option,-fno-stack-protector) \ + -D__DISABLE_EXPORTS GCOV_PROFILE := n KASAN_SANITIZE := n diff --git a/drivers/firmware/psci_checker.c b/drivers/firmware/psci_checker.c index bb1c068bff19..346943657962 100644 --- a/drivers/firmware/psci_checker.c +++ b/drivers/firmware/psci_checker.c @@ -77,28 +77,6 @@ static int psci_ops_check(void) return 0; } -static int find_cpu_groups(const struct cpumask *cpus, - const struct cpumask **cpu_groups) -{ - unsigned int nb = 0; - cpumask_var_t tmp; - - if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) - return -ENOMEM; - cpumask_copy(tmp, cpus); - - while (!cpumask_empty(tmp)) { - const struct cpumask *cpu_group = - topology_core_cpumask(cpumask_any(tmp)); - - cpu_groups[nb++] = cpu_group; - cpumask_andnot(tmp, tmp, cpu_group); - } - - free_cpumask_var(tmp); - return nb; -} - /* * offlined_cpus is a temporary array but passing it as an argument avoids * multiple allocations. @@ -166,29 +144,66 @@ static unsigned int down_and_up_cpus(const struct cpumask *cpus, return err; } +static void free_cpu_groups(int num, cpumask_var_t **pcpu_groups) +{ + int i; + cpumask_var_t *cpu_groups = *pcpu_groups; + + for (i = 0; i < num; ++i) + free_cpumask_var(cpu_groups[i]); + kfree(cpu_groups); +} + +static int alloc_init_cpu_groups(cpumask_var_t **pcpu_groups) +{ + int num_groups = 0; + cpumask_var_t tmp, *cpu_groups; + + if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) + return -ENOMEM; + + cpu_groups = kcalloc(nb_available_cpus, sizeof(cpu_groups), + GFP_KERNEL); + if (!cpu_groups) + return -ENOMEM; + + cpumask_copy(tmp, cpu_online_mask); + + while (!cpumask_empty(tmp)) { + const struct cpumask *cpu_group = + topology_core_cpumask(cpumask_any(tmp)); + + if (!alloc_cpumask_var(&cpu_groups[num_groups], GFP_KERNEL)) { + free_cpu_groups(num_groups, &cpu_groups); + return -ENOMEM; + } + cpumask_copy(cpu_groups[num_groups++], cpu_group); + cpumask_andnot(tmp, tmp, cpu_group); + } + + free_cpumask_var(tmp); + *pcpu_groups = cpu_groups; + + return num_groups; +} + static int hotplug_tests(void) { - int err; - cpumask_var_t offlined_cpus; - int i, nb_cpu_group; - const struct cpumask **cpu_groups; + int i, nb_cpu_group, err = -ENOMEM; + cpumask_var_t offlined_cpus, *cpu_groups; char *page_buf; - err = -ENOMEM; if (!alloc_cpumask_var(&offlined_cpus, GFP_KERNEL)) return err; - /* We may have up to nb_available_cpus cpu_groups. */ - cpu_groups = kmalloc_array(nb_available_cpus, sizeof(*cpu_groups), - GFP_KERNEL); - if (!cpu_groups) + + nb_cpu_group = alloc_init_cpu_groups(&cpu_groups); + if (nb_cpu_group < 0) goto out_free_cpus; page_buf = (char *)__get_free_page(GFP_KERNEL); if (!page_buf) goto out_free_cpu_groups; err = 0; - nb_cpu_group = find_cpu_groups(cpu_online_mask, cpu_groups); - /* * Of course the last CPU cannot be powered down and cpu_down() should * refuse doing that. @@ -212,7 +227,7 @@ static int hotplug_tests(void) free_page((unsigned long)page_buf); out_free_cpu_groups: - kfree(cpu_groups); + free_cpu_groups(nb_cpu_group, &cpu_groups); out_free_cpus: free_cpumask_var(offlined_cpus); return err; diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 6692888f04cf..a200a2174611 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -21,6 +21,10 @@ #define MBOX_DATA28(msg) ((msg) & ~0xf) #define MBOX_CHAN_PROPERTY 8 +#define MAX_RPI_FW_PROP_BUF_SIZE 32 + +static struct platform_device *rpi_hwmon; + struct rpi_firmware { struct mbox_client cl; struct mbox_chan *chan; /* The property channel. */ @@ -143,18 +147,22 @@ int rpi_firmware_property(struct rpi_firmware *fw, /* Single tags are very small (generally 8 bytes), so the * stack should be safe. */ - u8 data[buf_size + sizeof(struct rpi_firmware_property_tag_header)]; + u8 data[sizeof(struct rpi_firmware_property_tag_header) + + MAX_RPI_FW_PROP_BUF_SIZE]; struct rpi_firmware_property_tag_header *header = (struct rpi_firmware_property_tag_header *)data; int ret; + if (WARN_ON(buf_size > sizeof(data) - sizeof(*header))) + return -EINVAL; + header->tag = tag; header->buf_size = buf_size; header->req_resp_size = 0; memcpy(data + sizeof(struct rpi_firmware_property_tag_header), tag_data, buf_size); - ret = rpi_firmware_property_list(fw, &data, sizeof(data)); + ret = rpi_firmware_property_list(fw, &data, buf_size + sizeof(*header)); memcpy(tag_data, data + sizeof(struct rpi_firmware_property_tag_header), buf_size); @@ -183,6 +191,20 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) } } +static void +rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw) +{ + u32 packet; + int ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_THROTTLED, + &packet, sizeof(packet)); + + if (ret) + return; + + rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon", + -1, NULL, 0); +} + static int rpi_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -209,6 +231,7 @@ static int rpi_firmware_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fw); rpi_firmware_print_firmware_revision(fw); + rpi_register_hwmon_driver(dev, fw); return 0; } @@ -217,6 +240,8 @@ static int rpi_firmware_remove(struct platform_device *pdev) { struct rpi_firmware *fw = platform_get_drvdata(pdev); + platform_device_unregister(rpi_hwmon); + rpi_hwmon = NULL; mbox_free_channel(fw->chan); return 0; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f7a0f576f918..4f52c3a8ec99 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1049,6 +1049,12 @@ config GPIO_LP87565 This driver can also be built as a module. If so, the module will be called gpio-lp87565. +config GPIO_MADERA + tristate "Cirrus Logic Madera class codecs" + depends on PINCTRL_MADERA + help + Support for GPIOs on Cirrus Logic Madera class codecs. + config GPIO_MAX77620 tristate "GPIO support for PMIC MAX77620 and MAX20024" depends on MFD_MAX77620 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fc77989371be..c256aff66a65 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LP873X) += gpio-lp873x.o obj-$(CONFIG_GPIO_LP87565) += gpio-lp87565.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o +obj-$(CONFIG_GPIO_MADERA) += gpio-madera.o obj-$(CONFIG_GPIO_MAX3191X) += gpio-max3191x.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o diff --git a/drivers/gpio/gpio-madera.c b/drivers/gpio/gpio-madera.c new file mode 100644 index 000000000000..7ba68d1a0932 --- /dev/null +++ b/drivers/gpio/gpio-madera.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPIO support for Cirrus Logic Madera codecs + * + * Copyright (C) 2015-2018 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/gpio/driver.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/pdata.h> +#include <linux/mfd/madera/registers.h> + +struct madera_gpio { + struct madera *madera; + /* storage space for the gpio_chip we're using */ + struct gpio_chip gpio_chip; +}; + +static int madera_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct madera_gpio *madera_gpio = gpiochip_get_data(chip); + struct madera *madera = madera_gpio->madera; + unsigned int reg_offset = 2 * offset; + unsigned int val; + int ret; + + ret = regmap_read(madera->regmap, MADERA_GPIO1_CTRL_2 + reg_offset, + &val); + if (ret < 0) + return ret; + + return !!(val & MADERA_GP1_DIR_MASK); +} + +static int madera_gpio_direction_in(struct gpio_chip *chip, unsigned int offset) +{ + struct madera_gpio *madera_gpio = gpiochip_get_data(chip); + struct madera *madera = madera_gpio->madera; + unsigned int reg_offset = 2 * offset; + + return regmap_update_bits(madera->regmap, + MADERA_GPIO1_CTRL_2 + reg_offset, + MADERA_GP1_DIR_MASK, MADERA_GP1_DIR); +} + +static int madera_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct madera_gpio *madera_gpio = gpiochip_get_data(chip); + struct madera *madera = madera_gpio->madera; + unsigned int reg_offset = 2 * offset; + unsigned int val; + int ret; + + ret = regmap_read(madera->regmap, MADERA_GPIO1_CTRL_1 + reg_offset, + &val); + if (ret < 0) + return ret; + + return !!(val & MADERA_GP1_LVL_MASK); +} + +static int madera_gpio_direction_out(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct madera_gpio *madera_gpio = gpiochip_get_data(chip); + struct madera *madera = madera_gpio->madera; + unsigned int reg_offset = 2 * offset; + unsigned int reg_val = value ? MADERA_GP1_LVL : 0; + int ret; + + ret = regmap_update_bits(madera->regmap, + MADERA_GPIO1_CTRL_2 + reg_offset, + MADERA_GP1_DIR_MASK, 0); + if (ret < 0) + return ret; + + return regmap_update_bits(madera->regmap, + MADERA_GPIO1_CTRL_1 + reg_offset, + MADERA_GP1_LVL_MASK, reg_val); +} + +static void madera_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct madera_gpio *madera_gpio = gpiochip_get_data(chip); + struct madera *madera = madera_gpio->madera; + unsigned int reg_offset = 2 * offset; + unsigned int reg_val = value ? MADERA_GP1_LVL : 0; + int ret; + + ret = regmap_update_bits(madera->regmap, + MADERA_GPIO1_CTRL_1 + reg_offset, + MADERA_GP1_LVL_MASK, reg_val); + + /* set() doesn't return an error so log a warning */ + if (ret) + dev_warn(madera->dev, "Failed to write to 0x%x (%d)\n", + MADERA_GPIO1_CTRL_1 + reg_offset, ret); +} + +static struct gpio_chip madera_gpio_chip = { + .label = "madera", + .owner = THIS_MODULE, + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .get_direction = madera_gpio_get_direction, + .direction_input = madera_gpio_direction_in, + .get = madera_gpio_get, + .direction_output = madera_gpio_direction_out, + .set = madera_gpio_set, + .set_config = gpiochip_generic_config, + .can_sleep = true, +}; + +static int madera_gpio_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct madera_pdata *pdata = dev_get_platdata(madera->dev); + struct madera_gpio *madera_gpio; + int ret; + + madera_gpio = devm_kzalloc(&pdev->dev, sizeof(*madera_gpio), + GFP_KERNEL); + if (!madera_gpio) + return -ENOMEM; + + madera_gpio->madera = madera; + + /* Construct suitable gpio_chip from the template in madera_gpio_chip */ + madera_gpio->gpio_chip = madera_gpio_chip; + madera_gpio->gpio_chip.parent = pdev->dev.parent; + + switch (madera->type) { + case CS47L35: + madera_gpio->gpio_chip.ngpio = CS47L35_NUM_GPIOS; + break; + case CS47L85: + case WM1840: + madera_gpio->gpio_chip.ngpio = CS47L85_NUM_GPIOS; + break; + case CS47L90: + case CS47L91: + madera_gpio->gpio_chip.ngpio = CS47L90_NUM_GPIOS; + break; + default: + dev_err(&pdev->dev, "Unknown chip variant %d\n", madera->type); + return -EINVAL; + } + + /* We want to be usable on systems that don't use devicetree or acpi */ + if (pdata && pdata->gpio_base) + madera_gpio->gpio_chip.base = pdata->gpio_base; + else + madera_gpio->gpio_chip.base = -1; + + ret = devm_gpiochip_add_data(&pdev->dev, + &madera_gpio->gpio_chip, + madera_gpio); + if (ret < 0) { + dev_dbg(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; + } + + /* + * This is part of a composite MFD device which can only be used with + * the corresponding pinctrl driver. On all supported silicon the GPIO + * to pinctrl mapping is fixed in the silicon, so we register it + * explicitly instead of requiring a redundant gpio-ranges in the + * devicetree. + * In any case we also want to work on systems that don't use devicetree + * or acpi. + */ + ret = gpiochip_add_pin_range(&madera_gpio->gpio_chip, "madera-pinctrl", + 0, 0, madera_gpio->gpio_chip.ngpio); + if (ret) { + dev_dbg(&pdev->dev, "Failed to add pin range (%d)\n", ret); + return ret; + } + + return 0; +} + +static struct platform_driver madera_gpio_driver = { + .driver = { + .name = "madera-gpio", + }, + .probe = madera_gpio_probe, +}; + +module_platform_driver(madera_gpio_driver); + +MODULE_SOFTDEP("pre: pinctrl-madera"); +MODULE_DESCRIPTION("GPIO interface for Madera codecs"); +MODULE_AUTHOR("Nariman Poushin <nariman@opensource.cirrus.com>"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:madera-gpio"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 8a707d8bbb1c..f92597c292fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -206,11 +206,9 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, struct amdgpu_amdkfd_fence ***ef_list, unsigned int *ef_count) { - struct reservation_object_list *fobj; - struct reservation_object *resv; - unsigned int i = 0, j = 0, k = 0, shared_count; - unsigned int count = 0; - struct amdgpu_amdkfd_fence **fence_list; + struct reservation_object *resv = bo->tbo.resv; + struct reservation_object_list *old, *new; + unsigned int i, j, k; if (!ef && !ef_list) return -EINVAL; @@ -220,76 +218,67 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, *ef_count = 0; } - resv = bo->tbo.resv; - fobj = reservation_object_get_list(resv); - - if (!fobj) + old = reservation_object_get_list(resv); + if (!old) return 0; - preempt_disable(); - write_seqcount_begin(&resv->seq); + new = kmalloc(offsetof(typeof(*new), shared[old->shared_max]), + GFP_KERNEL); + if (!new) + return -ENOMEM; - /* Go through all the shared fences in the resevation object. If - * ef is specified and it exists in the list, remove it and reduce the - * count. If ef is not specified, then get the count of eviction fences - * present. + /* Go through all the shared fences in the resevation object and sort + * the interesting ones to the end of the list. */ - shared_count = fobj->shared_count; - for (i = 0; i < shared_count; ++i) { + for (i = 0, j = old->shared_count, k = 0; i < old->shared_count; ++i) { struct dma_fence *f; - f = rcu_dereference_protected(fobj->shared[i], + f = rcu_dereference_protected(old->shared[i], reservation_object_held(resv)); - if (ef) { - if (f->context == ef->base.context) { - dma_fence_put(f); - fobj->shared_count--; - } else { - RCU_INIT_POINTER(fobj->shared[j++], f); - } - } else if (to_amdgpu_amdkfd_fence(f)) - count++; + if ((ef && f->context == ef->base.context) || + (!ef && to_amdgpu_amdkfd_fence(f))) + RCU_INIT_POINTER(new->shared[--j], f); + else + RCU_INIT_POINTER(new->shared[k++], f); } - write_seqcount_end(&resv->seq); - preempt_enable(); - - if (ef || !count) - return 0; - - /* Alloc memory for count number of eviction fence pointers. Fill the - * ef_list array and ef_count - */ - fence_list = kcalloc(count, sizeof(struct amdgpu_amdkfd_fence *), - GFP_KERNEL); - if (!fence_list) - return -ENOMEM; + new->shared_max = old->shared_max; + new->shared_count = k; - preempt_disable(); - write_seqcount_begin(&resv->seq); + if (!ef) { + unsigned int count = old->shared_count - j; - j = 0; - for (i = 0; i < shared_count; ++i) { - struct dma_fence *f; - struct amdgpu_amdkfd_fence *efence; - - f = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(resv)); + /* Alloc memory for count number of eviction fence pointers. + * Fill the ef_list array and ef_count + */ + *ef_list = kcalloc(count, sizeof(**ef_list), GFP_KERNEL); + *ef_count = count; - efence = to_amdgpu_amdkfd_fence(f); - if (efence) { - fence_list[k++] = efence; - fobj->shared_count--; - } else { - RCU_INIT_POINTER(fobj->shared[j++], f); + if (!*ef_list) { + kfree(new); + return -ENOMEM; } } + /* Install the new fence list, seqcount provides the barriers */ + preempt_disable(); + write_seqcount_begin(&resv->seq); + RCU_INIT_POINTER(resv->fence, new); write_seqcount_end(&resv->seq); preempt_enable(); - *ef_list = fence_list; - *ef_count = k; + /* Drop the references to the removed fences or move them to ef_list */ + for (i = j, k = 0; i < old->shared_count; ++i) { + struct dma_fence *f; + + f = rcu_dereference_protected(new->shared[i], + reservation_object_held(resv)); + if (!ef) + (*ef_list)[k++] = to_amdgpu_amdkfd_fence(f); + else + dma_fence_put(f); + } + kfree_rcu(old, rcu); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 1e66dfd0e39c..8ab5ccbc14ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2274,7 +2274,7 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) case CHIP_VEGA10: case CHIP_VEGA12: case CHIP_VEGA20: -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: #endif return amdgpu_dc != 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index a365ea2383d1..e55508b39496 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -178,12 +178,18 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn) * * @amn: our notifier */ -static void amdgpu_mn_read_lock(struct amdgpu_mn *amn) +static int amdgpu_mn_read_lock(struct amdgpu_mn *amn, bool blockable) { - mutex_lock(&amn->read_lock); + if (blockable) + mutex_lock(&amn->read_lock); + else if (!mutex_trylock(&amn->read_lock)) + return -EAGAIN; + if (atomic_inc_return(&amn->recursion) == 1) down_read_non_owner(&amn->lock); mutex_unlock(&amn->read_lock); + + return 0; } /** @@ -239,10 +245,11 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, * Block for operations on BOs to finish and mark pages as accessed and * potentially dirty. */ -static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, +static int amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end, + bool blockable) { struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn); struct interval_tree_node *it; @@ -250,17 +257,28 @@ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, /* notification is exclusive, but interval is inclusive */ end -= 1; - amdgpu_mn_read_lock(amn); + /* TODO we should be able to split locking for interval tree and + * amdgpu_mn_invalidate_node + */ + if (amdgpu_mn_read_lock(amn, blockable)) + return -EAGAIN; it = interval_tree_iter_first(&amn->objects, start, end); while (it) { struct amdgpu_mn_node *node; + if (!blockable) { + amdgpu_mn_read_unlock(amn); + return -EAGAIN; + } + node = container_of(it, struct amdgpu_mn_node, it); it = interval_tree_iter_next(it, start, end); amdgpu_mn_invalidate_node(node, start, end); } + + return 0; } /** @@ -275,10 +293,11 @@ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, * necessitates evicting all user-mode queues of the process. The BOs * are restorted in amdgpu_mn_invalidate_range_end_hsa. */ -static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, +static int amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end, + bool blockable) { struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn); struct interval_tree_node *it; @@ -286,13 +305,19 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, /* notification is exclusive, but interval is inclusive */ end -= 1; - amdgpu_mn_read_lock(amn); + if (amdgpu_mn_read_lock(amn, blockable)) + return -EAGAIN; it = interval_tree_iter_first(&amn->objects, start, end); while (it) { struct amdgpu_mn_node *node; struct amdgpu_bo *bo; + if (!blockable) { + amdgpu_mn_read_unlock(amn); + return -EAGAIN; + } + node = container_of(it, struct amdgpu_mn_node, it); it = interval_tree_iter_next(it, start, end); @@ -304,6 +329,8 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, amdgpu_amdkfd_evict_userptr(mem, mm); } } + + return 0; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 86a0715d9431..1cafe8d83a4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -53,9 +53,8 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, int fd, enum drm_sched_priority priority) { - struct file *filp = fcheck(fd); + struct file *filp = fget(fd); struct drm_file *file; - struct pid *pid; struct amdgpu_fpriv *fpriv; struct amdgpu_ctx *ctx; uint32_t id; @@ -63,20 +62,12 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, if (!filp) return -EINVAL; - pid = get_pid(((struct drm_file *)filp->private_data)->pid); + file = filp->private_data; + fpriv = file->driver_priv; + idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id) + amdgpu_ctx_priority_override(ctx, priority); - mutex_lock(&adev->ddev->filelist_mutex); - list_for_each_entry(file, &adev->ddev->filelist, lhead) { - if (file->pid != pid) - continue; - - fpriv = file->driver_priv; - idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id) - amdgpu_ctx_priority_override(ctx, priority); - } - mutex_unlock(&adev->ddev->filelist_mutex); - - put_pid(pid); + fput(filp); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c index 52778de93ab0..2d4473557b0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c +++ b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c @@ -38,6 +38,7 @@ int vega20_reg_base_init(struct amdgpu_device *adev) adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); + adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); adev->reg_offset[UVD_HWIP][i] = (uint32_t *)(&(UVD_BASE.instance[i])); adev->reg_offset[VCE_HWIP][i] = (uint32_t *)(&(VCE_BASE.instance[i])); adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); @@ -46,6 +47,8 @@ int vega20_reg_base_init(struct amdgpu_device *adev) adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(SDMA0_BASE.instance[i])); adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(SDMA1_BASE.instance[i])); adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); + adev->reg_offset[NBIF_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); + adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 42c8ad105b05..88b57a5e9489 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -112,8 +112,8 @@ static u32 vi_smc_rreg(struct amdgpu_device *adev, u32 reg) u32 r; spin_lock_irqsave(&adev->smc_idx_lock, flags); - WREG32(mmSMC_IND_INDEX_11, (reg)); - r = RREG32(mmSMC_IND_DATA_11); + WREG32_NO_KIQ(mmSMC_IND_INDEX_11, (reg)); + r = RREG32_NO_KIQ(mmSMC_IND_DATA_11); spin_unlock_irqrestore(&adev->smc_idx_lock, flags); return r; } diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 325083b0297e..ed654a76c76a 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -4,11 +4,17 @@ menu "Display Engine Configuration" config DRM_AMD_DC bool "AMD DC - Enable new display engine" default y + select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and Raven ASICs. +config DRM_AMD_DC_DCN1_0 + def_bool n + help + RV family support for display engine + config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 34f34823bab5..800f481a6995 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -58,9 +58,7 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_edid.h> -#include "modules/inc/mod_freesync.h" - -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "ivsrcid/irqsrcs_dcn_1_0.h" #include "dcn/dcn_1_0_offset.h" @@ -1192,7 +1190,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) return 0; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* Register IRQ sources and initialize IRQ callbacks */ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) { @@ -1532,7 +1530,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) goto fail; } break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); @@ -1716,7 +1714,7 @@ static int dm_early_init(void *handle) adev->mode_info.num_dig = 6; adev->mode_info.plane_type = dm_plane_type_default; break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: adev->mode_info.num_crtc = 4; adev->mode_info.num_hpd = 4; diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 532a515fda9a..aed538a4d1ba 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -25,7 +25,7 @@ DC_LIBS = basics bios calcs dce gpio i2caux irq virtual -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 DC_LIBS += dcn10 dml endif diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c index 770ff89ba7e1..bbbcef566c55 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c @@ -55,7 +55,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2( case DCE_VERSION_11_22: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 416500e51b8d..95f332ee3e7e 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -38,7 +38,7 @@ CFLAGS_dcn_calc_math.o := $(calcs_ccflags) -Wno-tautological-compare BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 BW_CALCS += dcn_calcs.o dcn_calc_math.o dcn_calc_auto.o endif diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 733ac224e7fd..6ae050dc3220 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -52,6 +52,8 @@ #include "dm_helpers.h" #include "mem_input.h" #include "hubp.h" + +#include "dc_link_dp.h" #define DC_LOGGER \ dc->ctx->logger @@ -419,8 +421,17 @@ void dc_link_set_preferred_link_settings(struct dc *dc, struct dc_link_settings *link_setting, struct dc_link *link) { - link->preferred_link_setting = *link_setting; - dp_retrain_link_dp_test(link, link_setting, false); + struct dc_link_settings store_settings = *link_setting; + struct dc_stream_state *link_stream = + link->dc->current_state->res_ctx.pipe_ctx[0].stream; + + link->preferred_link_setting = store_settings; + if (link_stream) + decide_link_settings(link_stream, &store_settings); + + if ((store_settings.lane_count != LANE_COUNT_UNKNOWN) && + (store_settings.link_rate != LINK_RATE_UNKNOWN)) + dp_retrain_link_dp_test(link, &store_settings, false); } void dc_link_enable_hpd(const struct dc_link *link) @@ -476,7 +487,7 @@ static void destruct(struct dc *dc) kfree(dc->bw_dceip); dc->bw_dceip = NULL; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 kfree(dc->dcn_soc); dc->dcn_soc = NULL; @@ -492,7 +503,7 @@ static bool construct(struct dc *dc, struct dc_context *dc_ctx; struct bw_calcs_dceip *dc_dceip; struct bw_calcs_vbios *dc_vbios; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; #endif @@ -514,7 +525,7 @@ static bool construct(struct dc *dc, } dc->bw_vbios = dc_vbios; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 dcn_soc = kzalloc(sizeof(*dcn_soc), GFP_KERNEL); if (!dcn_soc) { dm_error("%s: failed to create dcn_soc\n", __func__); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index caece7c13bc6..e1ebdf7b5eaf 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -348,7 +348,7 @@ void context_clock_trace( struct dc *dc, struct dc_state *context) { -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) DC_LOGGER_INIT(dc->ctx->logger); CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 326b3e99b7e4..567867915d32 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1039,9 +1039,6 @@ static bool construct( link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index); - if (dc_ctx->dc_bios->integrated_info) - link->dp_ss_off = !!dc_ctx->dc_bios->integrated_info->dp_ss_control; - if (link->link_id.type != OBJECT_TYPE_CONNECTOR) { dm_error("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n", __func__, init_params->connector_index, @@ -1049,6 +1046,9 @@ static bool construct( goto create_fail; } + if (link->dc->res_pool->funcs->link_init) + link->dc->res_pool->funcs->link_init(link); + hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); if (hpd_gpio != NULL) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 1644f2a946b0..ea6beccfd89d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -41,7 +41,7 @@ #include "dce100/dce100_resource.h" #include "dce110/dce110_resource.h" #include "dce112/dce112_resource.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/dcn10_resource.h" #endif #include "dce120/dce120_resource.h" @@ -85,7 +85,7 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) case FAMILY_AI: dc_version = DCE_VERSION_12_0; break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case FAMILY_RV: dc_version = DCN_VERSION_1_0; break; @@ -136,7 +136,7 @@ struct resource_pool *dc_create_resource_pool( num_virtual_links, dc); break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: res_pool = dcn10_create_resource_pool( num_virtual_links, dc); @@ -1251,7 +1251,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream( } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) static int acquire_first_split_pipe( struct resource_context *res_ctx, const struct resource_pool *pool, @@ -1322,7 +1322,7 @@ bool dc_add_plane_to_context( free_pipe = acquire_free_pipe_for_stream(context, pool, stream); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (!free_pipe) { int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); if (pipe_idx >= 0) @@ -1920,7 +1920,7 @@ enum dc_status resource_map_pool_resources( /* acquire new resources */ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 if (pipe_idx < 0) pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e2f033d420a0..6c9990bef267 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -294,7 +294,7 @@ struct dc { /* Inputs into BW and WM calculations. */ struct bw_calcs_dceip *bw_dceip; struct bw_calcs_vbios *bw_vbios; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; struct display_mode_lib dml; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 439dcf3b596c..ca137757a69e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -592,7 +592,7 @@ static uint32_t dce110_get_pix_clk_dividers( case DCE_VERSION_11_2: case DCE_VERSION_11_22: case DCE_VERSION_12_0: -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: #endif @@ -909,7 +909,7 @@ static bool dce110_program_pix_clk( struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); struct bp_pixel_clock_parameters bp_pc_params = {0}; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) { unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; unsigned dp_dto_ref_kHz = 700000; @@ -982,7 +982,7 @@ static bool dce110_program_pix_clk( case DCE_VERSION_11_2: case DCE_VERSION_11_22: case DCE_VERSION_12_0: -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h index 801bb65707b3..c45e2f76189e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h @@ -55,7 +55,7 @@ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, mask_sh) -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \ SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 684da3db7568..fb1f373d08a1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -30,7 +30,7 @@ #include "bios_parser_interface.h" #include "dc.h" #include "dmcu.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn_calcs.h" #endif #include "core_types.h" @@ -106,7 +106,8 @@ enum dentist_base_divider_id { DENTIST_BASE_DID_1 = 0x08, DENTIST_BASE_DID_2 = 0x40, DENTIST_BASE_DID_3 = 0x60, - DENTIST_MAX_DID = 0x80 + DENTIST_BASE_DID_4 = 0x7e, + DENTIST_MAX_DID = 0x7f }; /* Starting point and step size for each divider range.*/ @@ -117,6 +118,8 @@ enum dentist_divider_range { DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ + DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */ + DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */ DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 }; @@ -133,9 +136,12 @@ static int dentist_get_divider_from_did(int did) } else if (did < DENTIST_BASE_DID_3) { return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP * (did - DENTIST_BASE_DID_2); - } else { + } else if (did < DENTIST_BASE_DID_4) { return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP * (did - DENTIST_BASE_DID_3); + } else { + return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP + * (did - DENTIST_BASE_DID_4); } } @@ -478,7 +484,7 @@ static void dce12_update_clocks(struct dccg *dccg, } } -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks) { bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; @@ -668,7 +674,7 @@ static void dce_update_clocks(struct dccg *dccg, } } -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 static const struct display_clock_funcs dcn1_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .set_dispclk = dce112_set_clock, @@ -823,7 +829,7 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) return &clk_dce->base; } -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dccg *dcn1_dccg_create(struct dc_context *ctx) { struct dc_debug_options *debug = &ctx->dc->debug; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index e5e44adc6c27..8a6b2d328467 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -111,7 +111,7 @@ struct dccg *dce112_dccg_create( struct dccg *dce120_dccg_create(struct dc_context *ctx); -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dccg *dcn1_dccg_create(struct dc_context *ctx); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index ca7989e4932b..dea40b322191 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -316,7 +316,7 @@ static void dce_get_psr_wait_loop( return; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) static void dcn10_get_dmcu_state(struct dmcu *dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); @@ -743,7 +743,7 @@ static const struct dmcu_funcs dce_funcs = { .is_dmcu_initialized = dce_is_dmcu_initialized }; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) static const struct dmcu_funcs dcn10_funcs = { .dmcu_init = dcn10_dmcu_init, .load_iram = dcn10_dmcu_load_iram, @@ -795,7 +795,7 @@ struct dmcu *dce_dmcu_create( return &dmcu_dce->base; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) struct dmcu *dcn10_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index b139b4017820..91642e684858 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -135,7 +135,7 @@ static void dce110_update_generic_info_packet( AFMT_GENERIC0_UPDATE, (packet_index == 0), AFMT_GENERIC2_UPDATE, (packet_index == 2)); } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(AFMT_VBI_PACKET_CONTROL1)) { switch (packet_index) { case 0: @@ -229,7 +229,7 @@ static void dce110_update_hdmi_info_packet( HDMI_GENERIC1_SEND, send, HDMI_GENERIC1_LINE, line); break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case 4: if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL2, @@ -274,7 +274,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space) { -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) uint32_t h_active_start; uint32_t v_active_start; uint32_t misc0 = 0; @@ -317,7 +317,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( if (enc110->se_mask->DP_VID_M_DOUBLE_VALUE_EN) REG_UPDATE(DP_VID_TIMING, DP_VID_M_DOUBLE_VALUE_EN, 1); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (enc110->se_mask->DP_VID_N_MUL) REG_UPDATE(DP_VID_TIMING, DP_VID_N_MUL, 1); #endif @@ -328,7 +328,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( break; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(DP_MSA_MISC)) misc1 = REG_READ(DP_MSA_MISC); #endif @@ -362,7 +362,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( /* set dynamic range and YCbCr range */ -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666: colorimetry_bpc = 0; @@ -441,7 +441,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( DP_DYN_RANGE, dynamic_range_rgb, DP_YCBCR_RANGE, dynamic_range_ycbcr); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(DP_MSA_COLORIMETRY)) REG_SET(DP_MSA_COLORIMETRY, 0, DP_MSA_MISC0, misc0); @@ -476,7 +476,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( crtc_timing->v_front_porch; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* start at begining of left border */ if (REG(DP_MSA_TIMING_PARAM2)) REG_SET_2(DP_MSA_TIMING_PARAM2, 0, @@ -751,7 +751,7 @@ static void dce110_stream_encoder_update_hdmi_info_packets( dce110_update_hdmi_info_packet(enc110, 3, &info_frame->hdrsmd); } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (enc110->se_mask->HDMI_DB_DISABLE) { /* for bring up, disable dp double TODO */ if (REG(HDMI_DB_CONTROL)) @@ -789,7 +789,7 @@ static void dce110_stream_encoder_stop_hdmi_info_packets( HDMI_GENERIC1_LINE, 0, HDMI_GENERIC1_SEND, 0); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* stop generic packets 2 & 3 on HDMI */ if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_SET_6(HDMI_GENERIC_PACKET_CONTROL2, 0, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 5450d4d38e8a..14384d9675a8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1250,7 +1250,7 @@ static void program_scaler(const struct dc *dc, { struct tg_color color = {0}; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* TOFPGA */ if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL) return; @@ -1588,7 +1588,13 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) bool can_eDP_fast_boot_optimize = false; if (edp_link) { - can_eDP_fast_boot_optimize = + /* this seems to cause blank screens on DCE8 */ + if ((dc->ctx->dce_version == DCE_VERSION_8_0) || + (dc->ctx->dce_version == DCE_VERSION_8_1) || + (dc->ctx->dce_version == DCE_VERSION_8_3)) + can_eDP_fast_boot_optimize = false; + else + can_eDP_fast_boot_optimize = edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc); } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index b9d9930a4974..562ee189d780 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -61,7 +61,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCE120) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 GPIO_DCN10 = hw_translate_dcn10.o hw_factory_dcn10.o AMD_DAL_GPIO_DCN10 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn10/,$(GPIO_DCN10)) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index 83df779984e5..0caee3523017 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -43,7 +43,7 @@ #include "dce80/hw_factory_dce80.h" #include "dce110/hw_factory_dce110.h" #include "dce120/hw_factory_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/hw_factory_dcn10.h" #endif @@ -81,7 +81,7 @@ bool dal_hw_factory_init( case DCE_VERSION_12_0: dal_hw_factory_dce120_init(factory); return true; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: dal_hw_factory_dcn10_init(factory); return true; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index e7541310480b..55c707488541 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -43,7 +43,7 @@ #include "dce80/hw_translate_dce80.h" #include "dce110/hw_translate_dce110.h" #include "dce120/hw_translate_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/hw_translate_dcn10.h" #endif @@ -78,7 +78,7 @@ bool dal_hw_translate_init( case DCE_VERSION_12_0: dal_hw_translate_dce120_init(translate); return true; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: dal_hw_translate_dcn10_init(translate); return true; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile index a851d07f0190..352885cb4d07 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile +++ b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile @@ -71,7 +71,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE112) ############################################################################### # DCN 1.0 family ############################################################################### -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 I2CAUX_DCN1 = i2caux_dcn10.o AMD_DAL_I2CAUX_DCN1 = $(addprefix $(AMDDALPATH)/dc/i2caux/dcn10/,$(I2CAUX_DCN1)) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c index f7ed355fc84f..9b0bcc6b769b 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c @@ -59,7 +59,7 @@ #include "dce120/i2caux_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/i2caux_dcn10.h" #endif @@ -91,7 +91,7 @@ struct i2caux *dal_i2caux_create( return dal_i2caux_dce100_create(ctx); case DCE_VERSION_12_0: return dal_i2caux_dce120_create(ctx); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: return dal_i2caux_dcn10_create(ctx); #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 9f33306f9014..c0b9ca13393b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -33,7 +33,7 @@ #include "dc_bios_types.h" #include "mem_input.h" #include "hubp.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "mpc.h" #endif @@ -92,6 +92,7 @@ struct resource_context; struct resource_funcs { void (*destroy)(struct resource_pool **pool); + void (*link_init)(struct dc_link *link); struct link_encoder *(*link_enc_create)( const struct encoder_init_data *init); @@ -221,7 +222,7 @@ struct pipe_ctx { struct pipe_ctx *top_pipe; struct pipe_ctx *bottom_pipe; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct _vcs_dpi_display_dlg_regs_st dlg_regs; struct _vcs_dpi_display_ttu_regs_st ttu_regs; struct _vcs_dpi_display_rq_regs_st rq_regs; @@ -276,7 +277,7 @@ struct dc_state { /* Note: these are big structures, do *not* put on stack! */ struct dm_pp_display_configuration pp_display_cfg; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dcn_bw_internal_vars dcn_bw_vars; #endif diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index a76ee600ecee..498515aad4a5 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -60,7 +60,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE12) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 IRQ_DCN1 = irq_service_dcn10.o AMD_DAL_IRQ_DCN1 = $(addprefix $(AMDDALPATH)/dc/irq/dcn10/,$(IRQ_DCN1)) diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index ae3fd0a235ba..604bea01fc13 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -36,7 +36,7 @@ #include "dce120/irq_service_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/irq_service_dcn10.h" #endif diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index c9fce9066ad8..a407892905af 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -48,7 +48,7 @@ #define dm_error(fmt, ...) DRM_ERROR(fmt, ##__VA_ARGS__) -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include <asm/fpu/api.h> #endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index 53207e76b0f3..6ef3c875fedd 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -75,10 +75,12 @@ int phm_set_power_state(struct pp_hwmgr *hwmgr, int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr) { + struct amdgpu_device *adev = NULL; int ret = -EINVAL;; PHM_FUNC_CHECK(hwmgr); + adev = hwmgr->adev; - if (smum_is_dpm_running(hwmgr)) { + if (smum_is_dpm_running(hwmgr) && !amdgpu_passthrough(adev)) { pr_info("dpm has been enabled\n"); return 0; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5dc742b27ca0..3c9fc99648b7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -116,6 +116,9 @@ static const struct edid_quirk { /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, + /* SDC panel of Lenovo B50-80 reports 8 bpc, but is a 6 bpc panel */ + { "SDC", 0x3652, EDID_QUIRK_FORCE_6BPC }, + /* Belinea 10 15 55 */ { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 2f00a37684a2..adefae58b5fc 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -108,7 +108,7 @@ static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -static int psbfb_vm_fault(struct vm_fault *vmf) +static vm_fault_t psbfb_vm_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct psb_framebuffer *psbfb = vma->vm_private_data; @@ -118,7 +118,7 @@ static int psbfb_vm_fault(struct vm_fault *vmf) int page_num; int i; unsigned long address; - int ret; + vm_fault_t ret = VM_FAULT_SIGBUS; unsigned long pfn; unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + gtt->offset; @@ -131,18 +131,14 @@ static int psbfb_vm_fault(struct vm_fault *vmf) for (i = 0; i < page_num; i++) { pfn = (phys_addr >> PAGE_SHIFT); - ret = vm_insert_mixed(vma, address, + ret = vmf_insert_mixed(vma, address, __pfn_to_pfn_t(pfn, PFN_DEV)); - if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) + if (unlikely(ret & VM_FAULT_ERROR)) break; - else if (unlikely(ret != 0)) { - ret = (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; - return ret; - } address += PAGE_SIZE; phys_addr += PAGE_SIZE; } - return VM_FAULT_NOPAGE; + return ret; } static void psbfb_vm_open(struct vm_area_struct *vma) diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index 913bf4c256fa..576f1b272f23 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -134,12 +134,13 @@ int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, * vma->vm_private_data points to the GEM object that is backing this * mapping. */ -int psb_gem_fault(struct vm_fault *vmf) +vm_fault_t psb_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj; struct gtt_range *r; - int ret; + int err; + vm_fault_t ret; unsigned long pfn; pgoff_t page_offset; struct drm_device *dev; @@ -158,9 +159,10 @@ int psb_gem_fault(struct vm_fault *vmf) /* For now the mmap pins the object and it stays pinned. As things stand that will do us no harm */ if (r->mmapping == 0) { - ret = psb_gtt_pin(r); - if (ret < 0) { - dev_err(dev->dev, "gma500: pin failed: %d\n", ret); + err = psb_gtt_pin(r); + if (err < 0) { + dev_err(dev->dev, "gma500: pin failed: %d\n", err); + ret = vmf_error(err); goto fail; } r->mmapping = 1; @@ -175,18 +177,9 @@ int psb_gem_fault(struct vm_fault *vmf) pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT; else pfn = page_to_pfn(r->pages[page_offset]); - ret = vm_insert_pfn(vma, vmf->address, pfn); - + ret = vmf_insert_pfn(vma, vmf->address, pfn); fail: mutex_unlock(&dev_priv->mmap_mutex); - switch (ret) { - case 0: - case -ERESTARTSYS: - case -EINTR: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + + return ret; } diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index e8300f509023..93d2f4000d2f 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -21,6 +21,7 @@ #define _PSB_DRV_H_ #include <linux/kref.h> +#include <linux/mm_types.h> #include <drm/drmP.h> #include <drm/drm_global.h> @@ -749,7 +750,7 @@ extern int psb_gem_get_aperture(struct drm_device *dev, void *data, struct drm_file *file); extern int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); -extern int psb_gem_fault(struct vm_fault *vmf); +extern vm_fault_t psb_gem_fault(struct vm_fault *vmf); /* psb_device.c */ extern const struct psb_ops psb_chip_ops; diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 5c607f2c707b..33a458b7f1fc 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -24,6 +24,7 @@ config DRM_I915 select IOSF_MBI select CRC32 select SND_HDA_I915 if SND_HDA_CORE + select CEC_CORE if CEC_NOTIFIER help Choose this option if you have a system that has "Intel Graphics Media Accelerator" or "HD Graphics" integrated graphics, diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index dcd6e230d16a..2c9b284036d1 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -112,10 +112,11 @@ static void del_object(struct i915_mmu_object *mo) mo->attached = false; } -static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, +static int i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end, + bool blockable) { struct i915_mmu_notifier *mn = container_of(_mn, struct i915_mmu_notifier, mn); @@ -124,7 +125,7 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, LIST_HEAD(cancelled); if (RB_EMPTY_ROOT(&mn->objects.rb_root)) - return; + return 0; /* interval ranges are inclusive, but invalidate range is exclusive */ end--; @@ -132,6 +133,10 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, spin_lock(&mn->lock); it = interval_tree_iter_first(&mn->objects, start, end); while (it) { + if (!blockable) { + spin_unlock(&mn->lock); + return -EAGAIN; + } /* The mmu_object is released late when destroying the * GEM object so it is entirely possible to gain a * reference on an object in the process of being freed @@ -154,6 +159,8 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, if (!list_empty(&cancelled)) flush_workqueue(mn->wq); + + return 0; } static const struct mmu_notifier_ops i915_gem_userptr_notifier = { diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index 00165ad55fb3..395dd2511568 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -43,7 +43,7 @@ #define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \ __stringify(x), (long)(x)) -#if GCC_VERSION >= 70000 +#if defined(GCC_VERSION) && GCC_VERSION >= 70000 #define add_overflows(A, B) \ __builtin_add_overflow_p((A), (B), (typeof((A) + (B)))0) #else diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index 9292001cdd14..138a1bc1818c 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -126,6 +126,30 @@ enum port { #define port_name(p) ((p) + 'A') +/* + * Ports identifier referenced from other drivers. + * Expected to remain stable over time + */ +static inline const char *port_identifier(enum port port) +{ + switch (port) { + case PORT_A: + return "Port A"; + case PORT_B: + return "Port B"; + case PORT_C: + return "Port C"; + case PORT_D: + return "Port D"; + case PORT_E: + return "Port E"; + case PORT_F: + return "Port F"; + default: + return "<invalid>"; + } +} + enum tc_port { PORT_TC_NONE = -1, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 17af06d8a43e..8fc61e96754f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -39,6 +39,7 @@ #include <drm/drm_dp_mst_helper.h> #include <drm/drm_rect.h> #include <drm/drm_atomic.h> +#include <media/cec-notifier.h> /** * __wait_for - magic wait macro @@ -1016,6 +1017,7 @@ struct intel_hdmi { bool has_audio; bool rgb_quant_range_selectable; struct intel_connector *attached_connector; + struct cec_notifier *cec_notifier; }; struct intel_dp_mst_encoder; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8363fbd18ee8..a9076402dcb0 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1899,6 +1899,8 @@ intel_hdmi_set_edid(struct drm_connector *connector) connected = true; } + cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid); + return connected; } @@ -1907,6 +1909,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) { enum drm_connector_status status; struct drm_i915_private *dev_priv = to_i915(connector->dev); + struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -1922,6 +1925,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS); + if (status != connector_status_connected) + cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier); + return status; } @@ -2062,6 +2068,8 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder, static void intel_hdmi_destroy(struct drm_connector *connector) { + if (intel_attached_hdmi(connector)->cec_notifier) + cec_notifier_put(intel_attached_hdmi(connector)->cec_notifier); kfree(to_intel_connector(connector)->detect_edid); drm_connector_cleanup(connector); kfree(connector); @@ -2382,6 +2390,11 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } + + intel_hdmi->cec_notifier = cec_notifier_get_conn(dev->dev, + port_identifier(port)); + if (!intel_hdmi->cec_notifier) + DRM_DEBUG_KMS("CEC notifier get failed\n"); } void intel_hdmi_init(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5b5d0a24e713..97964f7f2ace 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1385,6 +1385,9 @@ static const struct panel_desc innolux_tv123wam = { .width = 259, .height = 173, }, + .delay = { + .unprepare = 500, + }, }; static const struct drm_display_mode innolux_zj070na_01p_mode = { diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c index abd24975c9b1..f8b35df44c60 100644 --- a/drivers/gpu/drm/radeon/radeon_mn.c +++ b/drivers/gpu/drm/radeon/radeon_mn.c @@ -118,19 +118,27 @@ static void radeon_mn_release(struct mmu_notifier *mn, * We block for all BOs between start and end to be idle and * unmap them by move them into system domain again. */ -static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, +static int radeon_mn_invalidate_range_start(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end, + bool blockable) { struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn); struct ttm_operation_ctx ctx = { false, false }; struct interval_tree_node *it; + int ret = 0; /* notification is exclusive, but interval is inclusive */ end -= 1; - mutex_lock(&rmn->lock); + /* TODO we should be able to split locking for interval tree and + * the tear down. + */ + if (blockable) + mutex_lock(&rmn->lock); + else if (!mutex_trylock(&rmn->lock)) + return -EAGAIN; it = interval_tree_iter_first(&rmn->objects, start, end); while (it) { @@ -138,6 +146,11 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, struct radeon_bo *bo; long r; + if (!blockable) { + ret = -EAGAIN; + goto out_unlock; + } + node = container_of(it, struct radeon_mn_node, it); it = interval_tree_iter_next(it, start, end); @@ -166,7 +179,10 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, } } +out_unlock: mutex_unlock(&rmn->lock); + + return ret; } static const struct mmu_notifier_ops radeon_mn_ops = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index ddb1e9365a3e..b93c558dd86e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -51,51 +51,34 @@ static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, { struct vmwgfx_gmrid_man *gman = (struct vmwgfx_gmrid_man *)man->priv; - int ret = 0; int id; mem->mm_node = NULL; + id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); + if (id < 0) + return id; + spin_lock(&gman->lock); if (gman->max_gmr_pages > 0) { gman->used_gmr_pages += bo->num_pages; if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) - goto out_err_locked; + goto nospace; } - do { - spin_unlock(&gman->lock); - if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0)) { - ret = -ENOMEM; - goto out_err; - } - spin_lock(&gman->lock); - - ret = ida_get_new(&gman->gmr_ida, &id); - if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) { - ida_remove(&gman->gmr_ida, id); - ret = 0; - goto out_err_locked; - } - } while (ret == -EAGAIN); - - if (likely(ret == 0)) { - mem->mm_node = gman; - mem->start = id; - mem->num_pages = bo->num_pages; - } else - goto out_err_locked; + mem->mm_node = gman; + mem->start = id; + mem->num_pages = bo->num_pages; spin_unlock(&gman->lock); return 0; -out_err: - spin_lock(&gman->lock); -out_err_locked: +nospace: gman->used_gmr_pages -= bo->num_pages; spin_unlock(&gman->lock); - return ret; + ida_free(&gman->gmr_ida, id); + return 0; } static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, @@ -105,8 +88,8 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, (struct vmwgfx_gmrid_man *)man->priv; if (mem->mm_node) { + ida_free(&gman->gmr_ida, mem->start); spin_lock(&gman->lock); - ida_remove(&gman->gmr_ida, mem->start); gman->used_gmr_pages -= mem->num_pages; spin_unlock(&gman->lock); mem->mm_node = NULL; diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a49a10437c40..61e1953ff921 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -207,6 +207,16 @@ config HID_CORSAIR - Vengeance K90 - Scimitar PRO RGB +config HID_COUGAR + tristate "Cougar devices" + depends on HID + help + Support for Cougar devices that are not fully compliant with the + HID standard. + + Supported devices: + - Cougar 500k Gaming Keyboard + config HID_PRODIKEYS tristate "Prodikeys PC-MIDI Keyboard support" depends on HID && SND diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 511e1cbff768..bd7ac53b75c5 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o +obj-$(CONFIG_HID_COUGAR) += hid-cougar.o obj-$(CONFIG_HID_CP2112) += hid-cp2112.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3942ee61bd1c..3da354af7a0a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -128,9 +128,19 @@ static int open_collection(struct hid_parser *parser, unsigned type) usage = parser->local.usage[0]; - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { - hid_err(parser->device, "collection stack overflow\n"); - return -EINVAL; + if (parser->collection_stack_ptr == parser->collection_stack_size) { + unsigned int *collection_stack; + unsigned int new_size = parser->collection_stack_size + + HID_COLLECTION_STACK_SIZE; + + collection_stack = krealloc(parser->collection_stack, + new_size * sizeof(unsigned int), + GFP_KERNEL); + if (!collection_stack) + return -ENOMEM; + + parser->collection_stack = collection_stack; + parser->collection_stack_size = new_size; } if (parser->device->maxcollection == parser->device->collection_size) { @@ -840,6 +850,7 @@ static int hid_scan_report(struct hid_device *hid) break; } + kfree(parser->collection_stack); vfree(parser); return 0; } @@ -1939,6 +1950,29 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv) return hid_match_device(hdev, hdrv) != NULL; } +/** + * hid_compare_device_paths - check if both devices share the same path + * @hdev_a: hid device + * @hdev_b: hid device + * @separator: char to use as separator + * + * Check if two devices share the same path up to the last occurrence of + * the separator char. Both paths must exist (i.e., zero-length paths + * don't match). + */ +bool hid_compare_device_paths(struct hid_device *hdev_a, + struct hid_device *hdev_b, char separator) +{ + int n1 = strrchr(hdev_a->phys, separator) - hdev_a->phys; + int n2 = strrchr(hdev_b->phys, separator) - hdev_b->phys; + + if (n1 != n2 || n1 <= 0 || n2 <= 0) + return false; + + return !strncmp(hdev_a->phys, hdev_b->phys, n1); +} +EXPORT_SYMBOL_GPL(hid_compare_device_paths); + static int hid_device_probe(struct device *dev) { struct hid_driver *hdrv = to_hid_driver(dev->driver); diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c new file mode 100644 index 000000000000..ad2e87de7dc5 --- /dev/null +++ b/drivers/hid/hid-cougar.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID driver for Cougar 500k Gaming Keyboard + * + * Copyright (c) 2018 Daniel M. Lambea <dmlambea@gmail.com> + */ + +#include <linux/hid.h> +#include <linux/module.h> + +#include "hid-ids.h" + +MODULE_AUTHOR("Daniel M. Lambea <dmlambea@gmail.com>"); +MODULE_DESCRIPTION("Cougar 500k Gaming Keyboard"); +MODULE_LICENSE("GPL"); +MODULE_INFO(key_mappings, "G1-G6 are mapped to F13-F18"); + +static int cougar_g6_is_space = 1; +module_param_named(g6_is_space, cougar_g6_is_space, int, 0600); +MODULE_PARM_DESC(g6_is_space, + "If set, G6 programmable key sends SPACE instead of F18 (0=off, 1=on) (default=1)"); + + +#define COUGAR_VENDOR_USAGE 0xff00ff00 + +#define COUGAR_FIELD_CODE 1 +#define COUGAR_FIELD_ACTION 2 + +#define COUGAR_KEY_G1 0x83 +#define COUGAR_KEY_G2 0x84 +#define COUGAR_KEY_G3 0x85 +#define COUGAR_KEY_G4 0x86 +#define COUGAR_KEY_G5 0x87 +#define COUGAR_KEY_G6 0x78 +#define COUGAR_KEY_FN 0x0d +#define COUGAR_KEY_MR 0x6f +#define COUGAR_KEY_M1 0x80 +#define COUGAR_KEY_M2 0x81 +#define COUGAR_KEY_M3 0x82 +#define COUGAR_KEY_LEDS 0x67 +#define COUGAR_KEY_LOCK 0x6e + + +/* Default key mappings. The special key COUGAR_KEY_G6 is defined first + * because it is more frequent to use the spacebar rather than any other + * special keys. Depending on the value of the parameter 'g6_is_space', + * the mapping will be updated in the probe function. + */ +static unsigned char cougar_mapping[][2] = { + { COUGAR_KEY_G6, KEY_SPACE }, + { COUGAR_KEY_G1, KEY_F13 }, + { COUGAR_KEY_G2, KEY_F14 }, + { COUGAR_KEY_G3, KEY_F15 }, + { COUGAR_KEY_G4, KEY_F16 }, + { COUGAR_KEY_G5, KEY_F17 }, + { COUGAR_KEY_LOCK, KEY_SCREENLOCK }, +/* The following keys are handled by the hardware itself, so no special + * treatment is required: + { COUGAR_KEY_FN, KEY_RESERVED }, + { COUGAR_KEY_MR, KEY_RESERVED }, + { COUGAR_KEY_M1, KEY_RESERVED }, + { COUGAR_KEY_M2, KEY_RESERVED }, + { COUGAR_KEY_M3, KEY_RESERVED }, + { COUGAR_KEY_LEDS, KEY_RESERVED }, +*/ + { 0, 0 }, +}; + +struct cougar_shared { + struct list_head list; + struct kref kref; + bool enabled; + struct hid_device *dev; + struct input_dev *input; +}; + +struct cougar { + bool special_intf; + struct cougar_shared *shared; +}; + +static LIST_HEAD(cougar_udev_list); +static DEFINE_MUTEX(cougar_udev_list_lock); + +static void cougar_fix_g6_mapping(struct hid_device *hdev) +{ + int i; + + for (i = 0; cougar_mapping[i][0]; i++) { + if (cougar_mapping[i][0] == COUGAR_KEY_G6) { + cougar_mapping[i][1] = + cougar_g6_is_space ? KEY_SPACE : KEY_F18; + hid_info(hdev, "G6 mapped to %s\n", + cougar_g6_is_space ? "space" : "F18"); + return; + } + } + hid_warn(hdev, "no mapping defined for G6/spacebar"); +} + +/* + * Constant-friendly rdesc fixup for mouse interface + */ +static __u8 *cougar_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + if (rdesc[2] == 0x09 && rdesc[3] == 0x02 && + (rdesc[115] | rdesc[116] << 8) >= HID_MAX_USAGES) { + hid_info(hdev, + "usage count exceeds max: fixing up report descriptor\n"); + rdesc[115] = ((HID_MAX_USAGES-1) & 0xff); + rdesc[116] = ((HID_MAX_USAGES-1) >> 8); + } + return rdesc; +} + +static struct cougar_shared *cougar_get_shared_data(struct hid_device *hdev) +{ + struct cougar_shared *shared; + + /* Try to find an already-probed interface from the same device */ + list_for_each_entry(shared, &cougar_udev_list, list) { + if (hid_compare_device_paths(hdev, shared->dev, '/')) { + kref_get(&shared->kref); + return shared; + } + } + return NULL; +} + +static void cougar_release_shared_data(struct kref *kref) +{ + struct cougar_shared *shared = container_of(kref, + struct cougar_shared, kref); + + mutex_lock(&cougar_udev_list_lock); + list_del(&shared->list); + mutex_unlock(&cougar_udev_list_lock); + + kfree(shared); +} + +static void cougar_remove_shared_data(void *resource) +{ + struct cougar *cougar = resource; + + if (cougar->shared) { + kref_put(&cougar->shared->kref, cougar_release_shared_data); + cougar->shared = NULL; + } +} + +/* + * Bind the device group's shared data to this cougar struct. + * If no shared data exists for this group, create and initialize it. + */ +static int cougar_bind_shared_data(struct hid_device *hdev, struct cougar *cougar) +{ + struct cougar_shared *shared; + int error = 0; + + mutex_lock(&cougar_udev_list_lock); + + shared = cougar_get_shared_data(hdev); + if (!shared) { + shared = kzalloc(sizeof(*shared), GFP_KERNEL); + if (!shared) { + error = -ENOMEM; + goto out; + } + + kref_init(&shared->kref); + shared->dev = hdev; + list_add_tail(&shared->list, &cougar_udev_list); + } + + cougar->shared = shared; + + error = devm_add_action(&hdev->dev, cougar_remove_shared_data, cougar); + if (error) { + mutex_unlock(&cougar_udev_list_lock); + cougar_remove_shared_data(cougar); + return error; + } + +out: + mutex_unlock(&cougar_udev_list_lock); + return error; +} + +static int cougar_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct cougar *cougar; + struct hid_input *next, *hidinput = NULL; + unsigned int connect_mask; + int error; + + cougar = devm_kzalloc(&hdev->dev, sizeof(*cougar), GFP_KERNEL); + if (!cougar) + return -ENOMEM; + hid_set_drvdata(hdev, cougar); + + error = hid_parse(hdev); + if (error) { + hid_err(hdev, "parse failed\n"); + goto fail; + } + + if (hdev->collection->usage == COUGAR_VENDOR_USAGE) { + cougar->special_intf = true; + connect_mask = HID_CONNECT_HIDRAW; + } else + connect_mask = HID_CONNECT_DEFAULT; + + error = hid_hw_start(hdev, connect_mask); + if (error) { + hid_err(hdev, "hw start failed\n"); + goto fail; + } + + error = cougar_bind_shared_data(hdev, cougar); + if (error) + goto fail_stop_and_cleanup; + + /* The custom vendor interface will use the hid_input registered + * for the keyboard interface, in order to send translated key codes + * to it. + */ + if (hdev->collection->usage == HID_GD_KEYBOARD) { + cougar_fix_g6_mapping(hdev); + list_for_each_entry_safe(hidinput, next, &hdev->inputs, list) { + if (hidinput->registered && hidinput->input != NULL) { + cougar->shared->input = hidinput->input; + cougar->shared->enabled = true; + break; + } + } + } else if (hdev->collection->usage == COUGAR_VENDOR_USAGE) { + error = hid_hw_open(hdev); + if (error) + goto fail_stop_and_cleanup; + } + return 0; + +fail_stop_and_cleanup: + hid_hw_stop(hdev); +fail: + hid_set_drvdata(hdev, NULL); + return error; +} + +/* + * Convert events from vendor intf to input key events + */ +static int cougar_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *data, int size) +{ + struct cougar *cougar; + unsigned char code, action; + int i; + + cougar = hid_get_drvdata(hdev); + if (!cougar->special_intf || !cougar->shared || + !cougar->shared->input || !cougar->shared->enabled) + return 0; + + code = data[COUGAR_FIELD_CODE]; + action = data[COUGAR_FIELD_ACTION]; + for (i = 0; cougar_mapping[i][0]; i++) { + if (code == cougar_mapping[i][0]) { + input_event(cougar->shared->input, EV_KEY, + cougar_mapping[i][1], action); + input_sync(cougar->shared->input); + return 0; + } + } + hid_warn(hdev, "unmapped special key code %x: ignoring\n", code); + return 0; +} + +static void cougar_remove(struct hid_device *hdev) +{ + struct cougar *cougar = hid_get_drvdata(hdev); + + if (cougar) { + /* Stop the vendor intf to process more events */ + if (cougar->shared) + cougar->shared->enabled = false; + if (cougar->special_intf) + hid_hw_close(hdev); + } + hid_hw_stop(hdev); +} + +static struct hid_device_id cougar_id_table[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, + USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) }, + {} +}; +MODULE_DEVICE_TABLE(hid, cougar_id_table); + +static struct hid_driver cougar_driver = { + .name = "cougar", + .id_table = cougar_id_table, + .report_fixup = cougar_report_fixup, + .probe = cougar_probe, + .remove = cougar_remove, + .raw_event = cougar_raw_event, +}; + +module_hid_driver(cougar_driver); diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c index 803a725785cf..07e26c3567eb 100644 --- a/drivers/hid/hid-elan.c +++ b/drivers/hid/hid-elan.c @@ -19,38 +19,49 @@ #include "hid-ids.h" +#define ELAN_MT_I2C 0x5d #define ELAN_SINGLE_FINGER 0x81 #define ELAN_MT_FIRST_FINGER 0x82 #define ELAN_MT_SECOND_FINGER 0x83 #define ELAN_INPUT_REPORT_SIZE 8 +#define ELAN_I2C_REPORT_SIZE 32 +#define ELAN_FINGER_DATA_LEN 5 +#define ELAN_MAX_FINGERS 5 +#define ELAN_MAX_PRESSURE 255 +#define ELAN_TP_USB_INTF 1 + +#define ELAN_FEATURE_REPORT 0x0d +#define ELAN_FEATURE_SIZE 5 +#define ELAN_PARAM_MAX_X 6 +#define ELAN_PARAM_MAX_Y 7 +#define ELAN_PARAM_RES 8 #define ELAN_MUTE_LED_REPORT 0xBC #define ELAN_LED_REPORT_SIZE 8 -struct elan_touchpad_settings { - u8 max_fingers; - u16 max_x; - u16 max_y; - u8 max_area_x; - u8 max_area_y; - u8 max_w; - int usb_bInterfaceNumber; -}; +#define ELAN_HAS_LED BIT(0) struct elan_drvdata { struct input_dev *input; u8 prev_report[ELAN_INPUT_REPORT_SIZE]; struct led_classdev mute_led; u8 mute_led_state; - struct elan_touchpad_settings *settings; + u16 max_x; + u16 max_y; + u16 res_x; + u16 res_y; }; static int is_not_elan_touchpad(struct hid_device *hdev) { - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + if (hdev->bus == BUS_USB) { + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + + return (intf->altsetting->desc.bInterfaceNumber != + ELAN_TP_USB_INTF); + } - return (intf->altsetting->desc.bInterfaceNumber != drvdata->settings->usb_bInterfaceNumber); + return 0; } static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -62,12 +73,86 @@ static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi, if (field->report->id == ELAN_SINGLE_FINGER || field->report->id == ELAN_MT_FIRST_FINGER || - field->report->id == ELAN_MT_SECOND_FINGER) + field->report->id == ELAN_MT_SECOND_FINGER || + field->report->id == ELAN_MT_I2C) return -1; return 0; } +static int elan_get_device_param(struct hid_device *hdev, + unsigned char *dmabuf, unsigned char param) +{ + int ret; + + dmabuf[0] = ELAN_FEATURE_REPORT; + dmabuf[1] = 0x05; + dmabuf[2] = 0x03; + dmabuf[3] = param; + dmabuf[4] = 0x01; + + ret = hid_hw_raw_request(hdev, ELAN_FEATURE_REPORT, dmabuf, + ELAN_FEATURE_SIZE, HID_FEATURE_REPORT, + HID_REQ_SET_REPORT); + if (ret != ELAN_FEATURE_SIZE) { + hid_err(hdev, "Set report error for parm %d: %d\n", param, ret); + return ret; + } + + ret = hid_hw_raw_request(hdev, ELAN_FEATURE_REPORT, dmabuf, + ELAN_FEATURE_SIZE, HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret != ELAN_FEATURE_SIZE) { + hid_err(hdev, "Get report error for parm %d: %d\n", param, ret); + return ret; + } + + return 0; +} + +static unsigned int elan_convert_res(char val) +{ + /* + * (value from firmware) * 10 + 790 = dpi + * dpi * 10 / 254 = dots/mm + */ + return (val * 10 + 790) * 10 / 254; +} + +static int elan_get_device_params(struct hid_device *hdev) +{ + struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + unsigned char *dmabuf; + int ret; + + dmabuf = kmalloc(ELAN_FEATURE_SIZE, GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_MAX_X); + if (ret) + goto err; + + drvdata->max_x = (dmabuf[4] << 8) | dmabuf[3]; + + ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_MAX_Y); + if (ret) + goto err; + + drvdata->max_y = (dmabuf[4] << 8) | dmabuf[3]; + + ret = elan_get_device_param(hdev, dmabuf, ELAN_PARAM_RES); + if (ret) + goto err; + + drvdata->res_x = elan_convert_res(dmabuf[3]); + drvdata->res_y = elan_convert_res(dmabuf[4]); + +err: + kfree(dmabuf); + return ret; +} + static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) { int ret; @@ -77,6 +162,10 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) if (is_not_elan_touchpad(hdev)) return 0; + ret = elan_get_device_params(hdev); + if (ret) + return ret; + input = devm_input_allocate_device(&hdev->dev); if (!input) return -ENOMEM; @@ -90,25 +179,25 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) input->id.version = hdev->version; input->dev.parent = &hdev->dev; - input_set_abs_params(input, ABS_MT_POSITION_X, 0, - drvdata->settings->max_x, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, - drvdata->settings->max_y, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, - drvdata->settings->max_fingers, 0, 0); - input_set_abs_params(input, ABS_TOOL_WIDTH, 0, - drvdata->settings->max_w, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, 0, drvdata->max_x, + 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, drvdata->max_y, + 0, 0); + input_set_abs_params(input, ABS_MT_PRESSURE, 0, ELAN_MAX_PRESSURE, + 0, 0); __set_bit(BTN_LEFT, input->keybit); __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); - ret = input_mt_init_slots(input, drvdata->settings->max_fingers, - INPUT_MT_POINTER); + ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER); if (ret) { hid_err(hdev, "Failed to init elan MT slots: %d\n", ret); return ret; } + input_abs_set_res(input, ABS_X, drvdata->res_x); + input_abs_set_res(input, ABS_Y, drvdata->res_y); + ret = input_register_device(input); if (ret) { hid_err(hdev, "Failed to register elan input device: %d\n", @@ -126,7 +215,7 @@ static void elan_report_mt_slot(struct elan_drvdata *drvdata, u8 *data, unsigned int slot_num) { struct input_dev *input = drvdata->input; - int x, y, w; + int x, y, p; bool active = !!data; @@ -134,17 +223,17 @@ static void elan_report_mt_slot(struct elan_drvdata *drvdata, u8 *data, input_mt_report_slot_state(input, MT_TOOL_FINGER, active); if (active) { x = ((data[0] & 0xF0) << 4) | data[1]; - y = drvdata->settings->max_y - + y = drvdata->max_y - (((data[0] & 0x07) << 8) | data[2]); - w = data[4]; + p = data[4]; input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); - input_report_abs(input, ABS_TOOL_WIDTH, w); + input_report_abs(input, ABS_MT_PRESSURE, p); } } -static void elan_report_input(struct elan_drvdata *drvdata, u8 *data) +static void elan_usb_report_input(struct elan_drvdata *drvdata, u8 *data) { int i; struct input_dev *input = drvdata->input; @@ -162,7 +251,7 @@ static void elan_report_input(struct elan_drvdata *drvdata, u8 *data) * byte 5: x8 x7 x6 x5 x4 x3 x2 x1 * byte 6: y8 y7 y6 y5 y4 y3 y2 y1 * byte 7: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1 - * byte 8: w8 w7 w6 w5 w4 w3 w2 w1 + * byte 8: p8 p7 p6 p5 p4 p3 p2 p1 * * packet structure for ELAN_MT_SECOND_FINGER: * @@ -171,19 +260,21 @@ static void elan_report_input(struct elan_drvdata *drvdata, u8 *data) * byte 3: x8 x7 x6 x5 x4 x3 x2 x1 * byte 4: y8 y7 y6 y5 y4 y3 y2 y1 * byte 5: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1 - * byte 6: w8 w7 w6 w5 w4 w3 w2 w1 + * byte 6: p8 p7 p6 p5 p4 p3 p2 p1 * byte 7: 0 0 0 0 0 0 0 0 * byte 8: 0 0 0 0 0 0 0 0 * * f5-f1: finger touch bits * L: clickpad button - * sy / sx: not sure yet, but this looks like rectangular - * area for finger - * w: looks like finger width + * sy / sx: finger width / height expressed in traces, the total number + * of traces can be queried by doing a HID_REQ_SET_REPORT + * { 0x0d, 0x05, 0x03, 0x05, 0x01 } followed by a GET, in the + * returned buf, buf[3]=no-x-traces, buf[4]=no-y-traces. + * p: pressure */ if (data[0] == ELAN_SINGLE_FINGER) { - for (i = 0; i < drvdata->settings->max_fingers; i++) { + for (i = 0; i < ELAN_MAX_FINGERS; i++) { if (data[2] & BIT(i + 3)) elan_report_mt_slot(drvdata, data + 3, i); else @@ -210,7 +301,7 @@ static void elan_report_input(struct elan_drvdata *drvdata, u8 *data) if (prev_report[0] != ELAN_MT_FIRST_FINGER) return; - for (i = 0; i < drvdata->settings->max_fingers; i++) { + for (i = 0; i < ELAN_MAX_FINGERS; i++) { if (prev_report[2] & BIT(i + 3)) { if (!first) { first = 1; @@ -229,6 +320,46 @@ static void elan_report_input(struct elan_drvdata *drvdata, u8 *data) input_sync(input); } +static void elan_i2c_report_input(struct elan_drvdata *drvdata, u8 *data) +{ + struct input_dev *input = drvdata->input; + u8 *finger_data; + int i; + + /* + * Elan MT touchpads in i2c mode send finger data in the same format + * as in USB mode, but then with all fingers in a single packet. + * + * packet structure for ELAN_MT_I2C: + * + * byte 1: 1 0 0 1 1 1 0 1 // 0x5d + * byte 2: f5 f4 f3 f2 f1 0 0 L + * byte 3: x12 x11 x10 x9 0? y11 y10 y9 + * byte 4: x8 x7 x6 x5 x4 x3 x2 x1 + * byte 5: y8 y7 y6 y5 y4 y3 y2 y1 + * byte 6: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1 + * byte 7: p8 p7 p6 p5 p4 p3 p2 p1 + * byte 8-12: Same as byte 3-7 for second finger down + * byte 13-17: Same as byte 3-7 for third finger down + * byte 18-22: Same as byte 3-7 for fourth finger down + * byte 23-27: Same as byte 3-7 for fifth finger down + */ + + finger_data = data + 2; + for (i = 0; i < ELAN_MAX_FINGERS; i++) { + if (data[1] & BIT(i + 3)) { + elan_report_mt_slot(drvdata, finger_data, i); + finger_data += ELAN_FINGER_DATA_LEN; + } else { + elan_report_mt_slot(drvdata, NULL, i); + } + } + + input_report_key(input, BTN_LEFT, data[1] & 0x01); + input_mt_sync_frame(input); + input_sync(input); +} + static int elan_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { @@ -241,11 +372,16 @@ static int elan_raw_event(struct hid_device *hdev, data[0] == ELAN_MT_FIRST_FINGER || data[0] == ELAN_MT_SECOND_FINGER) { if (size == ELAN_INPUT_REPORT_SIZE) { - elan_report_input(drvdata, data); + elan_usb_report_input(drvdata, data); return 1; } } + if (data[0] == ELAN_MT_I2C && size == ELAN_I2C_REPORT_SIZE) { + elan_i2c_report_input(drvdata, data); + return 1; + } + return 0; } @@ -343,7 +479,6 @@ static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id) if (!drvdata) return -ENOMEM; - drvdata->settings = (struct elan_touchpad_settings *)id->driver_data; hid_set_drvdata(hdev, drvdata); ret = hid_parse(hdev); @@ -371,9 +506,11 @@ static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto err; - ret = elan_init_mute_led(hdev); - if (ret) - goto err; + if (id->driver_data & ELAN_HAS_LED) { + ret = elan_init_mute_led(hdev); + if (ret) + goto err; + } return 0; err: @@ -386,22 +523,14 @@ static void elan_remove(struct hid_device *hdev) hid_hw_stop(hdev); } -static const struct elan_touchpad_settings hp_x2_10_touchpad_data = { - .max_fingers = 5, - .max_x = 2930, - .max_y = 1250, - .max_area_x = 15, - .max_area_y = 15, - .max_w = 255, - .usb_bInterfaceNumber = 1, -}; - static const struct hid_device_id elan_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2), + .driver_data = ELAN_HAS_LED }, { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER), - (kernel_ulong_t)&hp_x2_10_touchpad_data}, + .driver_data = ELAN_HAS_LED }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_TOSHIBA_CLICK_L9W) }, { } }; - MODULE_DEVICE_TABLE(hid, elan_devices); static struct hid_driver elan_driver = { diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c7981ddd8776..79bdf0c7e351 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -369,6 +369,8 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 #define USB_VENDOR_ID_ELAN 0x04f3 +#define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401 +#define USB_DEVICE_ID_HP_X2 0x074d #define USB_DEVICE_ID_HP_X2_10_COVER 0x0755 #define USB_VENDOR_ID_ELECOM 0x056e @@ -1001,6 +1003,9 @@ #define USB_VENDOR_ID_SINO_LITE 0x1345 #define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008 +#define USB_VENDOR_ID_SOLID_YEAR 0x060b +#define USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD 0x500a + #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index ab93dd5927c3..4e94ea3e280a 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1550,6 +1550,9 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, case HID_GD_WIRELESS_RADIO_CTLS: suffix = "Wireless Radio Control"; break; + case HID_GD_SYSTEM_MULTIAXIS: + suffix = "System Multi Axis"; + break; default: break; } diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 96e7d3231d2f..72d983626afd 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -22,12 +22,13 @@ #include "hid-ids.h" -#define MS_HIDINPUT 0x01 -#define MS_ERGONOMY 0x02 -#define MS_PRESENTER 0x04 -#define MS_RDESC 0x08 -#define MS_NOGET 0x10 -#define MS_DUPLICATE_USAGES 0x20 +#define MS_HIDINPUT BIT(0) +#define MS_ERGONOMY BIT(1) +#define MS_PRESENTER BIT(2) +#define MS_RDESC BIT(3) +#define MS_NOGET BIT(4) +#define MS_DUPLICATE_USAGES BIT(5) +#define MS_SURFACE_DIAL BIT(6) static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) @@ -130,6 +131,30 @@ static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage, return 1; } +static int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, int *max) +{ + switch (usage->hid & HID_USAGE_PAGE) { + case 0xff070000: + /* fall-through */ + case HID_UP_DIGITIZER: + /* ignore those axis */ + return -1; + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + /* fall-through */ + case HID_GD_Y: + /* fall-through */ + case HID_GD_RFKILL_BTN: + /* ignore those axis */ + return -1; + } + } + + return 0; +} + static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -146,6 +171,13 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, ms_presenter_8k_quirk(hi, usage, bit, max)) return 1; + if (quirks & MS_SURFACE_DIAL) { + int ret = ms_surface_dial_quirk(hi, field, usage, bit, max); + + if (ret) + return ret; + } + return 0; } @@ -229,6 +261,9 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) if (quirks & MS_NOGET) hdev->quirks |= HID_QUIRK_NOGET; + if (quirks & MS_SURFACE_DIAL) + hdev->quirks |= HID_QUIRK_INPUT_PER_APP; + ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n"); @@ -281,6 +316,8 @@ static const struct hid_device_id ms_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B), + .driver_data = MS_SURFACE_DIAL }, { } }; MODULE_DEVICE_TABLE(hid, ms_devices); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 45968f7970f8..40fbb7c52723 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -28,14 +28,11 @@ */ /* - * This driver is regularly tested thanks to the tool hid-test[1]. - * This tool relies on hid-replay[2] and a database of hid devices[3]. + * This driver is regularly tested thanks to the test suite in hid-tools[1]. * Please run these regression tests before patching this module so that * your patch won't break existing known devices. * - * [1] https://github.com/bentiss/hid-test - * [2] https://github.com/bentiss/hid-replay - * [3] https://github.com/bentiss/hid-devices + * [1] https://gitlab.freedesktop.org/libevdev/hid-tools */ #include <linux/device.h> @@ -90,13 +87,54 @@ enum latency_mode { #define MT_IO_FLAGS_ACTIVE_SLOTS 1 #define MT_IO_FLAGS_PENDING_SLOTS 2 -struct mt_slot { - __s32 x, y, cx, cy, p, w, h, a; - __s32 contactid; /* the device ContactID assigned to this slot */ - bool touch_state; /* is the touch valid? */ - bool inrange_state; /* is the finger in proximity of the sensor? */ - bool confidence_state; /* is the touch made by a finger? */ - bool has_azimuth; /* the contact reports azimuth */ +static const bool mtrue = true; /* default for true */ +static const bool mfalse; /* default for false */ +static const __s32 mzero; /* default for 0 */ + +#define DEFAULT_TRUE ((void *)&mtrue) +#define DEFAULT_FALSE ((void *)&mfalse) +#define DEFAULT_ZERO ((void *)&mzero) + +struct mt_usages { + struct list_head list; + __s32 *x, *y, *cx, *cy, *p, *w, *h, *a; + __s32 *contactid; /* the device ContactID assigned to this slot */ + bool *tip_state; /* is the touch valid? */ + bool *inrange_state; /* is the finger in proximity of the sensor? */ + bool *confidence_state; /* is the touch made by a finger? */ +}; + +struct mt_application { + struct list_head list; + unsigned int application; + struct list_head mt_usages; /* mt usages list */ + + __s32 quirks; + + __s32 *scantime; /* scantime reported */ + __s32 scantime_logical_max; /* max value for raw scantime */ + + __s32 *raw_cc; /* contact count in the report */ + int left_button_state; /* left button state */ + unsigned int mt_flags; /* flags to pass to input-mt */ + + unsigned long *pending_palm_slots; /* slots where we reported palm + * and need to release */ + + __u8 num_received; /* how many contacts we received */ + __u8 num_expected; /* expected last contact index */ + __u8 buttons_count; /* number of physical buttons per touchpad */ + __u8 touches_by_report; /* how many touches are present in one report: + * 1 means we should use a serial protocol + * > 1 means hybrid (multitouch) protocol + */ + + __s32 dev_time; /* the scan time provided by the device */ + unsigned long jiffies; /* the frame's jiffies */ + int timestamp; /* the timestamp to be sent */ + int prev_scantime; /* scantime reported previously */ + + bool have_contact_count; }; struct mt_class { @@ -111,46 +149,30 @@ struct mt_class { bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */ }; -struct mt_fields { - unsigned usages[HID_MAX_FIELDS]; - unsigned int length; +struct mt_report_data { + struct list_head list; + struct hid_report *report; + struct mt_application *application; + bool is_mt_collection; }; struct mt_device { - struct mt_slot curdata; /* placeholder of incoming data */ struct mt_class mtclass; /* our mt device class */ struct timer_list release_timer; /* to release sticky fingers */ struct hid_device *hdev; /* hid_device we're attached to */ - struct mt_fields *fields; /* temporary placeholder for storing the - multitouch fields */ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ - int cc_index; /* contact count field index in the report */ - int cc_value_index; /* contact count value index in the field */ - int scantime_index; /* scantime field index in the report */ - int scantime_val_index; /* scantime value index in the field */ - int prev_scantime; /* scantime reported in the previous packet */ - int left_button_state; /* left button state */ - unsigned last_slot_field; /* the last field of a slot */ - unsigned mt_report_id; /* the report ID of the multitouch device */ __u8 inputmode_value; /* InputMode HID feature value */ - __u8 num_received; /* how many contacts we received */ - __u8 num_expected; /* expected last contact index */ __u8 maxcontacts; - __u8 touches_by_report; /* how many touches are present in one report: - * 1 means we should use a serial protocol - * > 1 means hybrid (multitouch) protocol */ - __u8 buttons_count; /* number of physical buttons per touchpad */ bool is_buttonpad; /* is this device a button pad? */ bool serial_maybe; /* need to check for serial protocol */ - bool curvalid; /* is the current contact valid? */ - unsigned mt_flags; /* flags to pass to input-mt */ - __s32 dev_time; /* the scan time provided by the device */ - unsigned long jiffies; /* the frame's jiffies */ - int timestamp; /* the timestamp to be sent */ + + struct list_head applications; + struct list_head reports; }; -static void mt_post_parse_default_settings(struct mt_device *td); -static void mt_post_parse(struct mt_device *td); +static void mt_post_parse_default_settings(struct mt_device *td, + struct mt_application *app); +static void mt_post_parse(struct mt_device *td, struct mt_application *app); /* classes of device behavior */ #define MT_CLS_DEFAULT 0x0001 @@ -203,15 +225,16 @@ static void mt_post_parse(struct mt_device *td); * to a valid contact that was just read. */ -static int cypress_compute_slot(struct mt_device *td) +static int cypress_compute_slot(struct mt_application *application, + struct mt_usages *slot) { - if (td->curdata.contactid != 0 || td->num_received == 0) - return td->curdata.contactid; + if (*slot->contactid != 0 || application->num_received == 0) + return *slot->contactid; else return -1; } -static struct mt_class mt_classes[] = { +static const struct mt_class mt_classes[] = { { .name = MT_CLS_DEFAULT, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE }, @@ -353,6 +376,7 @@ static ssize_t mt_set_quirks(struct device *dev, { struct hid_device *hdev = to_hid_device(dev); struct mt_device *td = hid_get_drvdata(hdev); + struct mt_application *application; unsigned long val; @@ -361,8 +385,11 @@ static ssize_t mt_set_quirks(struct device *dev, td->mtclass.quirks = val; - if (td->cc_index < 0) - td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + list_for_each_entry(application, &td->applications, list) { + application->quirks = val; + if (!application->have_contact_count) + application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + } return count; } @@ -457,41 +484,199 @@ static void set_abs(struct input_dev *input, unsigned int code, input_abs_set_res(input, code, hidinput_calc_abs_res(field, code)); } -static void mt_store_field(struct hid_usage *usage, struct mt_device *td, - struct hid_input *hi) +static struct mt_usages *mt_allocate_usage(struct hid_device *hdev, + struct mt_application *application) +{ + struct mt_usages *usage; + + usage = devm_kzalloc(&hdev->dev, sizeof(*usage), GFP_KERNEL); + if (!usage) + return NULL; + + /* set some defaults so we do not need to check for null pointers */ + usage->x = DEFAULT_ZERO; + usage->y = DEFAULT_ZERO; + usage->cx = DEFAULT_ZERO; + usage->cy = DEFAULT_ZERO; + usage->p = DEFAULT_ZERO; + usage->w = DEFAULT_ZERO; + usage->h = DEFAULT_ZERO; + usage->a = DEFAULT_ZERO; + usage->contactid = DEFAULT_ZERO; + usage->tip_state = DEFAULT_FALSE; + usage->inrange_state = DEFAULT_FALSE; + usage->confidence_state = DEFAULT_TRUE; + + list_add_tail(&usage->list, &application->mt_usages); + + return usage; +} + +static struct mt_application *mt_allocate_application(struct mt_device *td, + unsigned int application) +{ + struct mt_application *mt_application; + + mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application), + GFP_KERNEL); + if (!mt_application) + return NULL; + + mt_application->application = application; + INIT_LIST_HEAD(&mt_application->mt_usages); + + if (application == HID_DG_TOUCHSCREEN) + mt_application->mt_flags |= INPUT_MT_DIRECT; + + /* + * Model touchscreens providing buttons as touchpads. + */ + if (application == HID_DG_TOUCHPAD) { + mt_application->mt_flags |= INPUT_MT_POINTER; + td->inputmode_value = MT_INPUTMODE_TOUCHPAD; + } + + mt_application->scantime = DEFAULT_ZERO; + mt_application->raw_cc = DEFAULT_ZERO; + mt_application->quirks = td->mtclass.quirks; + + list_add_tail(&mt_application->list, &td->applications); + + return mt_application; +} + +static struct mt_application *mt_find_application(struct mt_device *td, + unsigned int application) +{ + struct mt_application *tmp, *mt_application = NULL; + + list_for_each_entry(tmp, &td->applications, list) { + if (application == tmp->application) { + mt_application = tmp; + break; + } + } + + if (!mt_application) + mt_application = mt_allocate_application(td, application); + + return mt_application; +} + +static struct mt_report_data *mt_allocate_report_data(struct mt_device *td, + struct hid_report *report) +{ + struct mt_report_data *rdata; + struct hid_field *field; + int r, n; + + rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL); + if (!rdata) + return NULL; + + rdata->report = report; + rdata->application = mt_find_application(td, report->application); + + if (!rdata->application) { + devm_kfree(&td->hdev->dev, rdata); + return NULL; + } + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + + if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) + continue; + + for (n = 0; n < field->report_count; n++) { + if (field->usage[n].hid == HID_DG_CONTACTID) + rdata->is_mt_collection = true; + } + } + + list_add_tail(&rdata->list, &td->reports); + + return rdata; +} + +static struct mt_report_data *mt_find_report_data(struct mt_device *td, + struct hid_report *report) { - struct mt_fields *f = td->fields; + struct mt_report_data *tmp, *rdata = NULL; - if (f->length >= HID_MAX_FIELDS) + list_for_each_entry(tmp, &td->reports, list) { + if (report == tmp->report) { + rdata = tmp; + break; + } + } + + if (!rdata) + rdata = mt_allocate_report_data(td, report); + + return rdata; +} + +static void mt_store_field(struct hid_device *hdev, + struct mt_application *application, + __s32 *value, + size_t offset) +{ + struct mt_usages *usage; + __s32 **target; + + if (list_empty(&application->mt_usages)) + usage = mt_allocate_usage(hdev, application); + else + usage = list_last_entry(&application->mt_usages, + struct mt_usages, + list); + + if (!usage) return; - f->usages[f->length++] = usage->hid; + target = (__s32 **)((char *)usage + offset); + + /* the value has already been filled, create a new slot */ + if (*target != DEFAULT_TRUE && + *target != DEFAULT_FALSE && + *target != DEFAULT_ZERO) { + usage = mt_allocate_usage(hdev, application); + if (!usage) + return; + + target = (__s32 **)((char *)usage + offset); + } + + *target = value; } +#define MT_STORE_FIELD(__name) \ + mt_store_field(hdev, app, \ + &field->value[usage->usage_index], \ + offsetof(struct mt_usages, __name)) + static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) + unsigned long **bit, int *max, struct mt_application *app) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; int code; struct hid_usage *prev_usage = NULL; - if (field->application == HID_DG_TOUCHSCREEN) - td->mt_flags |= INPUT_MT_DIRECT; - /* * Model touchscreens providing buttons as touchpads. */ - if (field->application == HID_DG_TOUCHPAD || + if (field->application == HID_DG_TOUCHSCREEN && (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { - td->mt_flags |= INPUT_MT_POINTER; + app->mt_flags |= INPUT_MT_POINTER; td->inputmode_value = MT_INPUTMODE_TOUCHPAD; } /* count the buttons on touchpads */ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) - td->buttons_count++; + app->buttons_count++; if (usage->usage_index) prev_usage = &field->usage[usage->usage_index - 1]; @@ -502,33 +687,40 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, switch (usage->hid) { case HID_GD_X: if (prev_usage && (prev_usage->hid == usage->hid)) { - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOOL_X); - set_abs(hi->input, ABS_MT_TOOL_X, field, - cls->sn_move); + code = ABS_MT_TOOL_X; + MT_STORE_FIELD(cx); } else { - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_X); - set_abs(hi->input, ABS_MT_POSITION_X, field, - cls->sn_move); + code = ABS_MT_POSITION_X; + MT_STORE_FIELD(x); + } + + set_abs(hi->input, code, field, cls->sn_move); + + /* + * A system multi-axis that exports X and Y has a high + * chance of being used directly on a surface + */ + if (field->application == HID_GD_SYSTEM_MULTIAXIS) { + __set_bit(INPUT_PROP_DIRECT, + hi->input->propbit); + input_set_abs_params(hi->input, + ABS_MT_TOOL_TYPE, + MT_TOOL_DIAL, + MT_TOOL_DIAL, 0, 0); } - mt_store_field(usage, td, hi); return 1; case HID_GD_Y: if (prev_usage && (prev_usage->hid == usage->hid)) { - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOOL_Y); - set_abs(hi->input, ABS_MT_TOOL_Y, field, - cls->sn_move); + code = ABS_MT_TOOL_Y; + MT_STORE_FIELD(cy); } else { - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_Y); - set_abs(hi->input, ABS_MT_POSITION_Y, field, - cls->sn_move); + code = ABS_MT_POSITION_Y; + MT_STORE_FIELD(y); } - mt_store_field(usage, td, hi); + set_abs(hi->input, code, field, cls->sn_move); + return 1; } return 0; @@ -536,43 +728,45 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_UP_DIGITIZER: switch (usage->hid) { case HID_DG_INRANGE: - if (cls->quirks & MT_QUIRK_HOVERING) { - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_DISTANCE); + if (app->quirks & MT_QUIRK_HOVERING) { input_set_abs_params(hi->input, ABS_MT_DISTANCE, 0, 1, 0, 0); } - mt_store_field(usage, td, hi); + MT_STORE_FIELD(inrange_state); return 1; case HID_DG_CONFIDENCE: if ((cls->name == MT_CLS_WIN_8 || cls->name == MT_CLS_WIN_8_DUAL) && - field->application == HID_DG_TOUCHPAD) - cls->quirks |= MT_QUIRK_CONFIDENCE; - mt_store_field(usage, td, hi); + (field->application == HID_DG_TOUCHPAD || + field->application == HID_DG_TOUCHSCREEN)) + app->quirks |= MT_QUIRK_CONFIDENCE; + + if (app->quirks & MT_QUIRK_CONFIDENCE) + input_set_abs_params(hi->input, + ABS_MT_TOOL_TYPE, + MT_TOOL_FINGER, + MT_TOOL_PALM, 0, 0); + + MT_STORE_FIELD(confidence_state); return 1; case HID_DG_TIPSWITCH: - hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); - input_set_capability(hi->input, EV_KEY, BTN_TOUCH); - mt_store_field(usage, td, hi); + if (field->application != HID_GD_SYSTEM_MULTIAXIS) + input_set_capability(hi->input, + EV_KEY, BTN_TOUCH); + MT_STORE_FIELD(tip_state); return 1; case HID_DG_CONTACTID: - mt_store_field(usage, td, hi); - td->touches_by_report++; - td->mt_report_id = field->report->id; + MT_STORE_FIELD(contactid); + app->touches_by_report++; return 1; case HID_DG_WIDTH: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MAJOR); - if (!(cls->quirks & MT_QUIRK_NO_AREA)) + if (!(app->quirks & MT_QUIRK_NO_AREA)) set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); - mt_store_field(usage, td, hi); + MT_STORE_FIELD(w); return 1; case HID_DG_HEIGHT: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MINOR); - if (!(cls->quirks & MT_QUIRK_NO_AREA)) { + if (!(app->quirks & MT_QUIRK_NO_AREA)) { set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, cls->sn_height); @@ -585,41 +779,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); } - mt_store_field(usage, td, hi); + MT_STORE_FIELD(h); return 1; case HID_DG_TIPPRESSURE: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_PRESSURE); set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); - mt_store_field(usage, td, hi); + MT_STORE_FIELD(p); return 1; case HID_DG_SCANTIME: - hid_map_usage(hi, usage, bit, max, - EV_MSC, MSC_TIMESTAMP); input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); - /* Ignore if indexes are out of bounds. */ - if (field->index >= field->report->maxfield || - usage->usage_index >= field->report_count) - return 1; - td->scantime_index = field->index; - td->scantime_val_index = usage->usage_index; - /* - * We don't set td->last_slot_field as scan time is - * global to the report. - */ + app->scantime = &field->value[usage->usage_index]; + app->scantime_logical_max = field->logical_maximum; return 1; case HID_DG_CONTACTCOUNT: - /* Ignore if indexes are out of bounds. */ - if (field->index >= field->report->maxfield || - usage->usage_index >= field->report_count) - return 1; - td->cc_index = field->index; - td->cc_value_index = usage->usage_index; + app->have_contact_count = true; + app->raw_cc = &field->value[usage->usage_index]; return 1; case HID_DG_AZIMUTH: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_ORIENTATION); /* * Azimuth has the range of [0, MAX) representing a full * revolution. Set ABS_MT_ORIENTATION to a quarter of @@ -630,11 +806,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->logical_maximum / 4, cls->sn_move ? field->logical_maximum / cls->sn_move : 0, 0); - mt_store_field(usage, td, hi); + MT_STORE_FIELD(a); return 1; case HID_DG_CONTACTMAX: - /* we don't set td->last_slot_field as contactcount and - * contact max are global to the report */ + /* contact max are global to the report */ return -1; case HID_DG_TOUCH: /* Legacy devices use TIPSWITCH and not TOUCH. @@ -650,10 +825,14 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, * MS PTP spec says that external buttons left and right have * usages 2 and 3. */ - if ((cls->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && + if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && field->application == HID_DG_TOUCHPAD && (usage->hid & HID_USAGE) > 1) code--; + + if (field->application == HID_GD_SYSTEM_MULTIAXIS) + code = BTN_0 + ((usage->hid - 1) & HID_USAGE); + hid_map_usage(hi, usage, bit, max, EV_KEY, code); input_set_capability(hi->input, EV_KEY, code); return 1; @@ -666,110 +845,68 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 0; } -static int mt_compute_slot(struct mt_device *td, struct input_dev *input) +static int mt_compute_slot(struct mt_device *td, struct mt_application *app, + struct mt_usages *slot, + struct input_dev *input) { - __s32 quirks = td->mtclass.quirks; + __s32 quirks = app->quirks; if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) - return td->curdata.contactid; + return *slot->contactid; if (quirks & MT_QUIRK_CYPRESS) - return cypress_compute_slot(td); + return cypress_compute_slot(app, slot); if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) - return td->num_received; + return app->num_received; if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) - return td->curdata.contactid - 1; + return *slot->contactid - 1; - return input_mt_get_slot_by_key(input, td->curdata.contactid); + return input_mt_get_slot_by_key(input, *slot->contactid); } -/* - * this function is called when a whole contact has been processed, - * so that it can assign it to a slot and store the data there - */ -static void mt_complete_slot(struct mt_device *td, struct input_dev *input) +static void mt_release_pending_palms(struct mt_device *td, + struct mt_application *app, + struct input_dev *input) { - if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) && - td->num_received >= td->num_expected) - return; - - if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) { - int active; - int slotnum = mt_compute_slot(td, input); - struct mt_slot *s = &td->curdata; - struct input_mt *mt = input->mt; + int slotnum; + bool need_sync = false; - if (slotnum < 0 || slotnum >= td->maxcontacts) - return; - - if ((td->mtclass.quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) { - struct input_mt_slot *slot = &mt->slots[slotnum]; - if (input_mt_is_active(slot) && - input_mt_is_used(mt, slot)) - return; - } - - if (!(td->mtclass.quirks & MT_QUIRK_CONFIDENCE)) - s->confidence_state = true; - active = (s->touch_state || s->inrange_state) && - s->confidence_state; + for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) { + clear_bit(slotnum, app->pending_palm_slots); input_mt_slot(input, slotnum); - input_mt_report_slot_state(input, MT_TOOL_FINGER, active); - if (active) { - /* this finger is in proximity of the sensor */ - int wide = (s->w > s->h); - int major = max(s->w, s->h); - int minor = min(s->w, s->h); - int orientation = wide; + input_mt_report_slot_state(input, MT_TOOL_PALM, false); - if (s->has_azimuth) - orientation = s->a; - - /* - * divided by two to match visual scale of touch - * for devices with this quirk - */ - if (td->mtclass.quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { - major = major >> 1; - minor = minor >> 1; - } - - input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); - input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx); - input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy); - input_event(input, EV_ABS, ABS_MT_DISTANCE, - !s->touch_state); - input_event(input, EV_ABS, ABS_MT_ORIENTATION, - orientation); - input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); - input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); - input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); - - set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); - } + need_sync = true; } - td->num_received++; + if (need_sync) { + input_mt_sync_frame(input); + input_sync(input); + } } /* * this function is called when a whole packet has been received and processed, * so that it can decide what to send to the input layer. */ -static void mt_sync_frame(struct mt_device *td, struct input_dev *input) +static void mt_sync_frame(struct mt_device *td, struct mt_application *app, + struct input_dev *input) { - if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) - input_event(input, EV_KEY, BTN_LEFT, td->left_button_state); + if (app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) + input_event(input, EV_KEY, BTN_LEFT, app->left_button_state); input_mt_sync_frame(input); - input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp); + input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp); input_sync(input); - td->num_received = 0; - td->left_button_state = 0; + + mt_release_pending_palms(td, app, input); + + app->num_received = 0; + app->left_button_state = 0; + if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); else @@ -777,17 +914,15 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input) clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); } -static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field, - __s32 value) +static int mt_compute_timestamp(struct mt_application *app, __s32 value) { - long delta = value - td->dev_time; - unsigned long jdelta = jiffies_to_usecs(jiffies - td->jiffies); + long delta = value - app->prev_scantime; + unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies); - td->jiffies = jiffies; - td->dev_time = value; + app->jiffies = jiffies; if (delta < 0) - delta += field->logical_maximum; + delta += app->scantime_logical_max; /* HID_DG_SCANTIME is expressed in 100us, we want it in us. */ delta *= 100; @@ -796,7 +931,7 @@ static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field, /* No data received for a while, resync the timestamp. */ return 0; else - return td->timestamp + delta; + return app->timestamp + delta; } static int mt_touch_event(struct hid_device *hid, struct hid_field *field, @@ -809,63 +944,90 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field, return 1; } -static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, - bool first_packet) +static int mt_process_slot(struct mt_device *td, struct input_dev *input, + struct mt_application *app, + struct mt_usages *slot) { - struct mt_device *td = hid_get_drvdata(hid); - __s32 quirks = td->mtclass.quirks; - struct input_dev *input = field->hidinput->input; + struct input_mt *mt = input->mt; + __s32 quirks = app->quirks; + bool valid = true; + bool confidence_state = true; + bool inrange_state = false; + int active; + int slotnum; + int tool = MT_TOOL_FINGER; + + if (!slot) + return -EINVAL; - if (hid->claimed & HID_CLAIMED_INPUT) { - switch (usage->hid) { - case HID_DG_INRANGE: - if (quirks & MT_QUIRK_VALID_IS_INRANGE) - td->curvalid = value; - if (quirks & MT_QUIRK_HOVERING) - td->curdata.inrange_state = value; - break; - case HID_DG_TIPSWITCH: - if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) - td->curvalid = value; - td->curdata.touch_state = value; - break; - case HID_DG_CONFIDENCE: - if (quirks & MT_QUIRK_CONFIDENCE) - td->curdata.confidence_state = value; - if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) - td->curvalid = value; - break; - case HID_DG_CONTACTID: - td->curdata.contactid = value; - break; - case HID_DG_TIPPRESSURE: - td->curdata.p = value; - break; - case HID_GD_X: - if (usage->code == ABS_MT_TOOL_X) - td->curdata.cx = value; - else - td->curdata.x = value; - break; - case HID_GD_Y: - if (usage->code == ABS_MT_TOOL_Y) - td->curdata.cy = value; - else - td->curdata.y = value; - break; - case HID_DG_WIDTH: - td->curdata.w = value; - break; - case HID_DG_HEIGHT: - td->curdata.h = value; - break; - case HID_DG_SCANTIME: - td->timestamp = mt_compute_timestamp(td, field, value); - break; - case HID_DG_CONTACTCOUNT: - break; - case HID_DG_AZIMUTH: + if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) && + app->num_received >= app->num_expected) + return -EAGAIN; + + if (!(quirks & MT_QUIRK_ALWAYS_VALID)) { + if (quirks & MT_QUIRK_VALID_IS_INRANGE) + valid = *slot->inrange_state; + if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) + valid = *slot->tip_state; + if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) + valid = *slot->confidence_state; + + if (!valid) + return 0; + } + + slotnum = mt_compute_slot(td, app, slot, input); + if (slotnum < 0 || slotnum >= td->maxcontacts) + return 0; + + if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) { + struct input_mt_slot *i_slot = &mt->slots[slotnum]; + + if (input_mt_is_active(i_slot) && + input_mt_is_used(mt, i_slot)) + return -EAGAIN; + } + + if (quirks & MT_QUIRK_CONFIDENCE) + confidence_state = *slot->confidence_state; + + if (quirks & MT_QUIRK_HOVERING) + inrange_state = *slot->inrange_state; + + active = *slot->tip_state || inrange_state; + + if (app->application == HID_GD_SYSTEM_MULTIAXIS) + tool = MT_TOOL_DIAL; + else if (unlikely(!confidence_state)) { + tool = MT_TOOL_PALM; + if (!active && + input_mt_is_active(&mt->slots[slotnum])) { + /* + * The non-confidence was reported for + * previously valid contact that is also no + * longer valid. We can't simply report + * lift-off as userspace will not be aware + * of non-confidence, so we need to split + * it into 2 events: active MT_TOOL_PALM + * and a separate liftoff. + */ + active = true; + set_bit(slotnum, app->pending_palm_slots); + } + } + + input_mt_slot(input, slotnum); + input_mt_report_slot_state(input, tool, active); + if (active) { + /* this finger is in proximity of the sensor */ + int wide = (*slot->w > *slot->h); + int major = max(*slot->w, *slot->h); + int minor = min(*slot->w, *slot->h); + int orientation = wide; + int max_azimuth; + int azimuth; + + if (slot->a != DEFAULT_ZERO) { /* * Azimuth is counter-clockwise and ranges from [0, MAX) * (a full revolution). Convert it to clockwise ranging @@ -876,77 +1038,107 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, * out of range to [-MAX/2, MAX/2] to report an upside * down ellipsis. */ - if (value > field->logical_maximum / 2) - value -= field->logical_maximum; - td->curdata.a = -value; - td->curdata.has_azimuth = true; - break; - case HID_DG_TOUCH: - /* do nothing */ - break; + azimuth = *slot->a; + max_azimuth = input_abs_get_max(input, + ABS_MT_ORIENTATION); + if (azimuth > max_azimuth * 2) + azimuth -= max_azimuth * 4; + orientation = -azimuth; + } - default: + if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { /* - * For Win8 PTP touchpads we should only look at - * non finger/touch events in the first_packet of - * a (possible) multi-packet frame. + * divided by two to match visual scale of touch + * for devices with this quirk */ - if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && - !first_packet) - return; + major = major >> 1; + minor = minor >> 1; + } - /* - * For Win8 PTP touchpads we map both the clickpad click - * and any "external" left buttons to BTN_LEFT if a - * device claims to have both we need to report 1 for - * BTN_LEFT if either is pressed, so we or all values - * together and report the result in mt_sync_frame(). - */ - if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && - usage->type == EV_KEY && usage->code == BTN_LEFT) { - td->left_button_state |= value; - return; - } + input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y); + input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx); + input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy); + input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state); + input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation); + input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); + + set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); + } - if (usage->type) - input_event(input, usage->type, usage->code, - value); + return 0; +} + +static void mt_process_mt_event(struct hid_device *hid, + struct mt_application *app, + struct hid_field *field, + struct hid_usage *usage, + __s32 value, + bool first_packet) +{ + __s32 quirks = app->quirks; + struct input_dev *input = field->hidinput->input; + + if (!usage->type || !(hid->claimed & HID_CLAIMED_INPUT)) + return; + + if (quirks & MT_QUIRK_WIN8_PTP_BUTTONS) { + + /* + * For Win8 PTP touchpads we should only look at + * non finger/touch events in the first_packet of a + * (possible) multi-packet frame. + */ + if (!first_packet) return; - } - if (usage->usage_index + 1 == field->report_count) { - /* we only take into account the last report. */ - if (usage->hid == td->last_slot_field) - mt_complete_slot(td, field->hidinput->input); + /* + * For Win8 PTP touchpads we map both the clickpad click + * and any "external" left buttons to BTN_LEFT if a + * device claims to have both we need to report 1 for + * BTN_LEFT if either is pressed, so we or all values + * together and report the result in mt_sync_frame(). + */ + if (usage->type == EV_KEY && usage->code == BTN_LEFT) { + app->left_button_state |= value; + return; } - } + + input_event(input, usage->type, usage->code, value); } -static void mt_touch_report(struct hid_device *hid, struct hid_report *report) +static void mt_touch_report(struct hid_device *hid, + struct mt_report_data *rdata) { struct mt_device *td = hid_get_drvdata(hid); + struct hid_report *report = rdata->report; + struct mt_application *app = rdata->application; struct hid_field *field; + struct input_dev *input; + struct mt_usages *slot; bool first_packet; unsigned count; - int r, n, scantime = 0; + int r, n; + int scantime = 0; + int contact_count = -1; /* sticky fingers release in progress, abort */ if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) return; + scantime = *app->scantime; + app->timestamp = mt_compute_timestamp(app, scantime); + if (app->raw_cc != DEFAULT_ZERO) + contact_count = *app->raw_cc; + /* * Includes multi-packet support where subsequent * packets are sent with zero contactcount. */ - if (td->scantime_index >= 0) { - field = report->field[td->scantime_index]; - scantime = field->value[td->scantime_val_index]; - } - if (td->cc_index >= 0) { - struct hid_field *field = report->field[td->cc_index]; - int value = field->value[td->cc_value_index]; - + if (contact_count >= 0) { /* * For Win8 PTPs the first packet (td->num_received == 0) may * have a contactcount of 0 if there only is a button event. @@ -954,16 +1146,25 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) * of a possible multi-packet frame be checking that the * timestamp has changed. */ - if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && - td->num_received == 0 && td->prev_scantime != scantime) - td->num_expected = value; + if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && + app->num_received == 0 && + app->prev_scantime != scantime) + app->num_expected = contact_count; /* A non 0 contact count always indicates a first packet */ - else if (value) - td->num_expected = value; + else if (contact_count) + app->num_expected = contact_count; + } + app->prev_scantime = scantime; + + first_packet = app->num_received == 0; + + input = report->field[0]->hidinput->input; + + list_for_each_entry(slot, &app->mt_usages, list) { + if (!mt_process_slot(td, input, app, slot)) + app->num_received++; } - td->prev_scantime = scantime; - first_packet = td->num_received == 0; for (r = 0; r < report->maxfield; r++) { field = report->field[r]; count = field->report_count; @@ -972,12 +1173,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) continue; for (n = 0; n < count; n++) - mt_process_mt_event(hid, field, &field->usage[n], - field->value[n], first_packet); + mt_process_mt_event(hid, app, field, + &field->usage[n], field->value[n], + first_packet); } - if (td->num_received >= td->num_expected) - mt_sync_frame(td, report->field[0]->hidinput->input); + if (app->num_received >= app->num_expected) + mt_sync_frame(td, app, input); /* * Windows 8 specs says 2 things: @@ -997,7 +1199,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) * only affect laggish machines and the ones that have a firmware * defect. */ - if (td->mtclass.quirks & MT_QUIRK_STICKY_FINGERS) { + if (app->quirks & MT_QUIRK_STICKY_FINGERS) { if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags)) mod_timer(&td->release_timer, jiffies + msecs_to_jiffies(100)); @@ -1009,7 +1211,8 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) } static int mt_touch_input_configured(struct hid_device *hdev, - struct hid_input *hi) + struct hid_input *hi, + struct mt_application *app) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; @@ -1019,28 +1222,36 @@ static int mt_touch_input_configured(struct hid_device *hdev, if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; - mt_post_parse(td); + mt_post_parse(td, app); if (td->serial_maybe) - mt_post_parse_default_settings(td); + mt_post_parse_default_settings(td, app); if (cls->is_indirect) - td->mt_flags |= INPUT_MT_POINTER; + app->mt_flags |= INPUT_MT_POINTER; - if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) - td->mt_flags |= INPUT_MT_DROP_UNUSED; + if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) + app->mt_flags |= INPUT_MT_DROP_UNUSED; /* check for clickpads */ - if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1)) + if ((app->mt_flags & INPUT_MT_POINTER) && + (app->buttons_count == 1)) td->is_buttonpad = true; if (td->is_buttonpad) __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); - ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags); + app->pending_palm_slots = devm_kcalloc(&hi->input->dev, + BITS_TO_LONGS(td->maxcontacts), + sizeof(long), + GFP_KERNEL); + if (!app->pending_palm_slots) + return -ENOMEM; + + ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags); if (ret) return ret; - td->mt_flags = 0; + app->mt_flags = 0; return 0; } @@ -1051,6 +1262,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, unsigned long **bit, int *max) { struct mt_device *td = hid_get_drvdata(hdev); + struct mt_application *application; + struct mt_report_data *rdata; + + rdata = mt_find_report_data(td, field->report); + if (!rdata) { + hid_err(hdev, "failed to allocate data for report\n"); + return 0; + } + + application = rdata->application; /* * If mtclass.export_all_inputs is not set, only map fields from @@ -1066,8 +1287,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, field->application != HID_GD_SYSTEM_CONTROL && field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_GD_WIRELESS_RADIO_CTLS && + field->application != HID_GD_SYSTEM_MULTIAXIS && !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && - td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP)) + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP)) return -1; /* @@ -1076,7 +1298,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, * map usages to input keys. */ if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && - td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP && + application->quirks & MT_QUIRK_ASUS_CUSTOM_UP && (usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) { set_bit(EV_REP, hi->input->evbit); if (field->flags & HID_MAIN_ITEM_VARIABLE) @@ -1093,23 +1315,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } - /* - * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" - * for the stylus. - * The check for mt_report_id ensures we don't process - * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical - * collection, but within the report ID. - */ - if (field->physical == HID_DG_STYLUS) - return 0; - else if ((field->physical == 0) && - (field->report->id != td->mt_report_id) && - (td->mt_report_id != -1)) - return 0; - - if (field->application == HID_DG_TOUCHSCREEN || - field->application == HID_DG_TOUCHPAD) - return mt_touch_input_mapping(hdev, hi, field, usage, bit, max); + if (rdata->is_mt_collection) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max, + application); /* let hid-core decide for the others */ return 0; @@ -1119,15 +1327,11 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* - * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" - * for the stylus. - */ - if (field->physical == HID_DG_STYLUS) - return 0; + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_report_data *rdata; - if (field->application == HID_DG_TOUCHSCREEN || - field->application == HID_DG_TOUCHPAD) { + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) { /* We own these mappings, tell hid-input to ignore them */ return -1; } @@ -1140,8 +1344,10 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct mt_device *td = hid_get_drvdata(hid); + struct mt_report_data *rdata; - if (field->report->id == td->mt_report_id) + rdata = mt_find_report_data(td, field->report); + if (rdata && rdata->is_mt_collection) return mt_touch_event(hid, field, usage, value); return 0; @@ -1151,12 +1357,14 @@ static void mt_report(struct hid_device *hid, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hid); struct hid_field *field = report->field[0]; + struct mt_report_data *rdata; if (!(hid->claimed & HID_CLAIMED_INPUT)) return; - if (report->id == td->mt_report_id) - return mt_touch_report(hid, report); + rdata = mt_find_report_data(td, report); + if (rdata && rdata->is_mt_collection) + return mt_touch_report(hid, rdata); if (field && field->hidinput && field->hidinput->input) input_sync(field->hidinput->input); @@ -1197,9 +1405,9 @@ static bool mt_need_to_apply_feature(struct hid_device *hdev, return true; case HID_DG_CONTACTMAX: - if (td->mtclass.maxcontacts) { + if (cls->maxcontacts) { max = min_t(int, field->logical_maximum, - td->mtclass.maxcontacts); + cls->maxcontacts); if (field->value[index] != max) { field->value[index] = max; return true; @@ -1259,12 +1467,13 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency, } } -static void mt_post_parse_default_settings(struct mt_device *td) +static void mt_post_parse_default_settings(struct mt_device *td, + struct mt_application *app) { - __s32 quirks = td->mtclass.quirks; + __s32 quirks = app->quirks; /* unknown serial device needs special quirks */ - if (td->touches_by_report == 1) { + if (list_is_singular(&app->mt_usages)) { quirks |= MT_QUIRK_ALWAYS_VALID; quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; quirks &= ~MT_QUIRK_VALID_IS_INRANGE; @@ -1272,21 +1481,13 @@ static void mt_post_parse_default_settings(struct mt_device *td) quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } - td->mtclass.quirks = quirks; + app->quirks = quirks; } -static void mt_post_parse(struct mt_device *td) +static void mt_post_parse(struct mt_device *td, struct mt_application *app) { - struct mt_fields *f = td->fields; - struct mt_class *cls = &td->mtclass; - - if (td->touches_by_report > 0) { - int field_count_per_touch = f->length / td->touches_by_report; - td->last_slot_field = f->usages[field_count_per_touch - 1]; - } - - if (td->cc_index < 0) - cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + if (!app->have_contact_count) + app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) @@ -1295,13 +1496,24 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) char *name; const char *suffix = NULL; unsigned int application = 0; + struct mt_report_data *rdata; + struct mt_application *mt_application = NULL; struct hid_report *report; int ret; list_for_each_entry(report, &hi->reports, hidinput_list) { application = report->application; - if (report->id == td->mt_report_id) { - ret = mt_touch_input_configured(hdev, hi); + rdata = mt_find_report_data(td, report); + if (!rdata) { + hid_err(hdev, "failed to allocate data for report\n"); + return -ENOMEM; + } + + mt_application = rdata->application; + + if (rdata->is_mt_collection) { + ret = mt_touch_input_configured(hdev, hi, + mt_application); if (ret) return ret; } @@ -1327,6 +1539,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) case HID_GD_SYSTEM_CONTROL: case HID_CP_CONSUMER_CONTROL: case HID_GD_WIRELESS_RADIO_CTLS: + case HID_GD_SYSTEM_MULTIAXIS: /* already handled by hid core */ break; case HID_DG_TOUCHSCREEN: @@ -1390,6 +1603,7 @@ static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage) static void mt_release_contacts(struct hid_device *hid) { struct hid_input *hidinput; + struct mt_application *application; struct mt_device *td = hid_get_drvdata(hid); list_for_each_entry(hidinput, &hid->inputs, list) { @@ -1409,7 +1623,9 @@ static void mt_release_contacts(struct hid_device *hid) } } - td->num_received = 0; + list_for_each_entry(application, &td->applications, list) { + application->num_received = 0; + } } static void mt_expired_timeout(struct timer_list *t) @@ -1432,7 +1648,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; struct mt_device *td; - struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ + const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ for (i = 0; mt_classes[i].name ; i++) { if (id->driver_data == mt_classes[i].name) { @@ -1449,17 +1665,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->hdev = hdev; td->mtclass = *mtclass; td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; - td->cc_index = -1; - td->scantime_index = -1; - td->mt_report_id = -1; hid_set_drvdata(hdev, td); - td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields), - GFP_KERNEL); - if (!td->fields) { - dev_err(&hdev->dev, "cannot allocate multitouch fields data\n"); - return -ENOMEM; - } + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) td->serial_maybe = true; @@ -1496,10 +1705,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); - /* release .fields memory as it is not used anymore */ - devm_kfree(&hdev->dev, td->fields); - td->fields = NULL; - return 0; } diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 43b1c7234316..9bc6f4867cb3 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -955,6 +955,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = sysfs_create_group(&hdev->dev.kobj, &ntrig_attribute_group); + if (ret) + hid_err(hdev, "cannot create sysfs group\n"); return 0; err_free: diff --git a/drivers/hid/hid-redragon.c b/drivers/hid/hid-redragon.c index daf59578bf93..73c9d4c4fa34 100644 --- a/drivers/hid/hid-redragon.c +++ b/drivers/hid/hid-redragon.c @@ -44,29 +44,6 @@ static __u8 *redragon_report_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } -static int redragon_probe(struct hid_device *dev, - const struct hid_device_id *id) -{ - int ret; - - ret = hid_parse(dev); - if (ret) { - hid_err(dev, "parse failed\n"); - return ret; - } - - /* do not register unused input device */ - if (dev->maxapplication == 1) - return 0; - - ret = hid_hw_start(dev, HID_CONNECT_DEFAULT); - if (ret) { - hid_err(dev, "hw start failed\n"); - return ret; - } - - return 0; -} static const struct hid_device_id redragon_devices[] = { {HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_REDRAGON_ASURA)}, {} @@ -77,8 +54,7 @@ MODULE_DEVICE_TABLE(hid, redragon_devices); static struct hid_driver redragon_driver = { .name = "redragon", .id_table = redragon_devices, - .report_fixup = redragon_report_fixup, - .probe = redragon_probe + .report_fixup = redragon_report_fixup }; module_hid_driver(redragon_driver); diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index e475c5073c99..9671a4bad643 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1353,7 +1353,7 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, char *name; int ret; - sc->touchpad = input_allocate_device(); + sc->touchpad = devm_input_allocate_device(&sc->hdev->dev); if (!sc->touchpad) return -ENOMEM; @@ -1370,11 +1370,9 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, * DS4 compatible non-Sony devices with different names. */ name_sz = strlen(sc->hdev->name) + sizeof(DS4_TOUCHPAD_SUFFIX); - name = kzalloc(name_sz, GFP_KERNEL); - if (!name) { - ret = -ENOMEM; - goto err; - } + name = devm_kzalloc(&sc->hdev->dev, name_sz, GFP_KERNEL); + if (!name) + return -ENOMEM; snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name); sc->touchpad->name = name; @@ -1403,34 +1401,13 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER); if (ret < 0) - goto err; + return ret; ret = input_register_device(sc->touchpad); if (ret < 0) - goto err; + return ret; return 0; - -err: - kfree(sc->touchpad->name); - sc->touchpad->name = NULL; - - input_free_device(sc->touchpad); - sc->touchpad = NULL; - - return ret; -} - -static void sony_unregister_touchpad(struct sony_sc *sc) -{ - if (!sc->touchpad) - return; - - kfree(sc->touchpad->name); - sc->touchpad->name = NULL; - - input_unregister_device(sc->touchpad); - sc->touchpad = NULL; } static int sony_register_sensors(struct sony_sc *sc) @@ -1440,7 +1417,7 @@ static int sony_register_sensors(struct sony_sc *sc) int ret; int range; - sc->sensor_dev = input_allocate_device(); + sc->sensor_dev = devm_input_allocate_device(&sc->hdev->dev); if (!sc->sensor_dev) return -ENOMEM; @@ -1457,11 +1434,9 @@ static int sony_register_sensors(struct sony_sc *sc) * DS4 compatible non-Sony devices with different names. */ name_sz = strlen(sc->hdev->name) + sizeof(SENSOR_SUFFIX); - name = kzalloc(name_sz, GFP_KERNEL); - if (!name) { - ret = -ENOMEM; - goto err; - } + name = devm_kzalloc(&sc->hdev->dev, name_sz, GFP_KERNEL); + if (!name) + return -ENOMEM; snprintf(name, name_sz, "%s" SENSOR_SUFFIX, sc->hdev->name); sc->sensor_dev->name = name; @@ -1503,33 +1478,11 @@ static int sony_register_sensors(struct sony_sc *sc) ret = input_register_device(sc->sensor_dev); if (ret < 0) - goto err; + return ret; return 0; - -err: - kfree(sc->sensor_dev->name); - sc->sensor_dev->name = NULL; - - input_free_device(sc->sensor_dev); - sc->sensor_dev = NULL; - - return ret; } -static void sony_unregister_sensors(struct sony_sc *sc) -{ - if (!sc->sensor_dev) - return; - - kfree(sc->sensor_dev->name); - sc->sensor_dev->name = NULL; - - input_unregister_device(sc->sensor_dev); - sc->sensor_dev = NULL; -} - - /* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * to "operational". Without this, the ps3 controller will not report any @@ -1987,25 +1940,6 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on, return 0; } -static void sony_leds_remove(struct sony_sc *sc) -{ - struct led_classdev *led; - int n; - - BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); - - for (n = 0; n < sc->led_count; n++) { - led = sc->leds[n]; - sc->leds[n] = NULL; - if (!led) - continue; - led_classdev_unregister(led); - kfree(led); - } - - sc->led_count = 0; -} - static int sony_leds_init(struct sony_sc *sc) { struct hid_device *hdev = sc->hdev; @@ -2078,11 +2012,10 @@ static int sony_leds_init(struct sony_sc *sc) if (use_ds4_names) name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2; - led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL); + led = devm_kzalloc(&hdev->dev, sizeof(struct led_classdev) + name_sz, GFP_KERNEL); if (!led) { hid_err(hdev, "Couldn't allocate memory for LED %d\n", n); - ret = -ENOMEM; - goto error_leds; + return -ENOMEM; } name = (void *)(&led[1]); @@ -2103,21 +2036,14 @@ static int sony_leds_init(struct sony_sc *sc) sc->leds[n] = led; - ret = led_classdev_register(&hdev->dev, led); + ret = devm_led_classdev_register(&hdev->dev, led); if (ret) { hid_err(hdev, "Failed to register LED %d\n", n); - sc->leds[n] = NULL; - kfree(led); - goto error_leds; + return ret; } } - return ret; - -error_leds: - sony_leds_remove(sc); - - return ret; + return 0; } static void sixaxis_send_output_report(struct sony_sc *sc) @@ -2276,16 +2202,20 @@ static int sony_allocate_output_report(struct sony_sc *sc) if ((sc->quirks & SIXAXIS_CONTROLLER) || (sc->quirks & NAVIGATION_CONTROLLER)) sc->output_report_dmabuf = - kmalloc(sizeof(union sixaxis_output_report_01), + devm_kmalloc(&sc->hdev->dev, + sizeof(union sixaxis_output_report_01), GFP_KERNEL); else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) - sc->output_report_dmabuf = kmalloc(DS4_OUTPUT_REPORT_0x11_SIZE, + sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev, + DS4_OUTPUT_REPORT_0x11_SIZE, GFP_KERNEL); else if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) - sc->output_report_dmabuf = kmalloc(DS4_OUTPUT_REPORT_0x05_SIZE, + sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev, + DS4_OUTPUT_REPORT_0x05_SIZE, GFP_KERNEL); else if (sc->quirks & MOTION_CONTROLLER) - sc->output_report_dmabuf = kmalloc(MOTION_REPORT_0x02_SIZE, + sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev, + MOTION_REPORT_0x02_SIZE, GFP_KERNEL); else return 0; @@ -2392,36 +2322,21 @@ static int sony_battery_probe(struct sony_sc *sc, int append_dev_id) sc->battery_desc.get_property = sony_battery_get_property; sc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; sc->battery_desc.use_for_apm = 0; - sc->battery_desc.name = kasprintf(GFP_KERNEL, battery_str_fmt, - sc->mac_address, sc->device_id); + sc->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + battery_str_fmt, sc->mac_address, sc->device_id); if (!sc->battery_desc.name) return -ENOMEM; - sc->battery = power_supply_register(&hdev->dev, &sc->battery_desc, + sc->battery = devm_power_supply_register(&hdev->dev, &sc->battery_desc, &psy_cfg); if (IS_ERR(sc->battery)) { ret = PTR_ERR(sc->battery); hid_err(hdev, "Unable to register battery device\n"); - goto err_free; + return ret; } power_supply_powers(sc->battery, &hdev->dev); return 0; - -err_free: - kfree(sc->battery_desc.name); - sc->battery_desc.name = NULL; - return ret; -} - -static void sony_battery_remove(struct sony_sc *sc) -{ - if (!sc->battery_desc.name) - return; - - power_supply_unregister(sc->battery); - kfree(sc->battery_desc.name); - sc->battery_desc.name = NULL; } /* @@ -2879,16 +2794,7 @@ err_stop: device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); if (sc->hw_version) device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); - if (sc->quirks & SONY_LED_SUPPORT) - sony_leds_remove(sc); - if (sc->quirks & SONY_BATTERY_SUPPORT) - sony_battery_remove(sc); - if (sc->touchpad) - sony_unregister_touchpad(sc); - if (sc->sensor_dev) - sony_unregister_sensors(sc); sony_cancel_work_sync(sc); - kfree(sc->output_report_dmabuf); sony_remove_dev_list(sc); sony_release_device_id(sc); hid_hw_stop(hdev); @@ -2965,18 +2871,6 @@ static void sony_remove(struct hid_device *hdev) hid_hw_close(hdev); - if (sc->quirks & SONY_LED_SUPPORT) - sony_leds_remove(sc); - - if (sc->quirks & SONY_BATTERY_SUPPORT) - sony_battery_remove(sc); - - if (sc->touchpad) - sony_unregister_touchpad(sc); - - if (sc->sensor_dev) - sony_unregister_sensors(sc); - if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); @@ -2988,8 +2882,6 @@ static void sony_remove(struct hid_device *hdev) sony_cancel_work_sync(sc); - kfree(sc->output_report_dmabuf); - sony_remove_dev_list(sc); sony_release_device_id(sc); diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 579884ebd94d..7780da4fe897 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -455,6 +455,12 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem) return WIIMOTE_EXT_BALANCE_BOARD; if (rmem[4] == 0x01 && rmem[5] == 0x20) return WIIMOTE_EXT_PRO_CONTROLLER; + if (rmem[0] == 0x01 && rmem[1] == 0x00 && + rmem[4] == 0x01 && rmem[5] == 0x03) + return WIIMOTE_EXT_DRUMS; + if (rmem[0] == 0x00 && rmem[1] == 0x00 && + rmem[4] == 0x01 && rmem[5] == 0x03) + return WIIMOTE_EXT_GUITAR; return WIIMOTE_EXT_UNKNOWN; } @@ -488,6 +494,8 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype) /* map MP with correct pass-through mode */ switch (exttype) { case WIIMOTE_EXT_CLASSIC_CONTROLLER: + case WIIMOTE_EXT_DRUMS: + case WIIMOTE_EXT_GUITAR: wmem = 0x07; break; case WIIMOTE_EXT_NUNCHUK: @@ -1075,6 +1083,8 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = { [WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller", [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board", [WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller", + [WIIMOTE_EXT_DRUMS] = "Nintendo Wii Drums", + [WIIMOTE_EXT_GUITAR] = "Nintendo Wii Guitar", }; /* @@ -1660,6 +1670,10 @@ static ssize_t wiimote_ext_show(struct device *dev, return sprintf(buf, "balanceboard\n"); case WIIMOTE_EXT_PRO_CONTROLLER: return sprintf(buf, "procontroller\n"); + case WIIMOTE_EXT_DRUMS: + return sprintf(buf, "drums\n"); + case WIIMOTE_EXT_GUITAR: + return sprintf(buf, "guitar\n"); case WIIMOTE_EXT_UNKNOWN: /* fallthrough */ default: diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c index c830ed39348f..aa72eb9a8e2f 100644 --- a/drivers/hid/hid-wiimote-modules.c +++ b/drivers/hid/hid-wiimote-modules.c @@ -1950,6 +1950,444 @@ static const struct wiimod_ops wiimod_pro = { }; /* + * Drums + * Guitar-Hero, Rock-Band and other games came bundled with drums which can + * be plugged as extension to a Wiimote. Drum-reports are still not entirely + * figured out, but the most important information is known. + * We create a separate device for drums and report all information via this + * input device. + */ + +static inline void wiimod_drums_report_pressure(struct wiimote_data *wdata, + __u8 none, __u8 which, + __u8 pressure, __u8 onoff, + __u8 *store, __u16 code, + __u8 which_code) +{ + static const __u8 default_pressure = 3; + + if (!none && which == which_code) { + *store = pressure; + input_report_abs(wdata->extension.input, code, *store); + } else if (onoff != !!*store) { + *store = onoff ? default_pressure : 0; + input_report_abs(wdata->extension.input, code, *store); + } +} + +static void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext) +{ + __u8 pressure, which, none, hhp, sx, sy; + __u8 o, r, y, g, b, bass, bm, bp; + + /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 1 | 0 | 0 | SX <5:0> | + * 2 | 0 | 0 | SY <5:0> | + * -----+-----+-----+-----------------------------+-----+ + * 3 | HPP | NON | WHICH <5:1> | ? | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 | ? | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 6 | O | R | Y | G | B | BSS | 1 | 1 | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * All buttons are 0 if pressed + * + * With Motion+ enabled, the following bits will get invalid: + * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 1 | 0 | 0 | SX <5:1> |XXXXX| + * 2 | 0 | 0 | SY <5:1> |XXXXX| + * -----+-----+-----+-----------------------------+-----+ + * 3 | HPP | NON | WHICH <5:1> | ? | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 5 | ? | 1 | 1 | B- | 1 | B+ | 1 |XXXXX| + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 6 | O | R | Y | G | B | BSS |XXXXX|XXXXX| + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + */ + + pressure = 7 - (ext[3] >> 5); + which = (ext[2] >> 1) & 0x1f; + none = !!(ext[2] & 0x40); + hhp = !(ext[2] & 0x80); + sx = ext[0] & 0x3f; + sy = ext[1] & 0x3f; + o = !(ext[5] & 0x80); + r = !(ext[5] & 0x40); + y = !(ext[5] & 0x20); + g = !(ext[5] & 0x10); + b = !(ext[5] & 0x08); + bass = !(ext[5] & 0x04); + bm = !(ext[4] & 0x10); + bp = !(ext[4] & 0x04); + + if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { + sx &= 0x3e; + sy &= 0x3e; + } + + wiimod_drums_report_pressure(wdata, none, which, pressure, + o, &wdata->state.pressure_drums[0], + ABS_HAT2Y, 0x0e); + wiimod_drums_report_pressure(wdata, none, which, pressure, + r, &wdata->state.pressure_drums[1], + ABS_HAT0X, 0x19); + wiimod_drums_report_pressure(wdata, none, which, pressure, + y, &wdata->state.pressure_drums[2], + ABS_HAT2X, 0x11); + wiimod_drums_report_pressure(wdata, none, which, pressure, + g, &wdata->state.pressure_drums[3], + ABS_HAT1X, 0x12); + wiimod_drums_report_pressure(wdata, none, which, pressure, + b, &wdata->state.pressure_drums[4], + ABS_HAT0Y, 0x0f); + + /* Bass shares pressure with hi-hat (set via hhp) */ + wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure, + bass, &wdata->state.pressure_drums[5], + ABS_HAT3X, 0x1b); + /* Hi-hat has no on/off values, just pressure. Force to off/0. */ + wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure, + 0, &wdata->state.pressure_drums[6], + ABS_HAT3Y, 0x0e); + + input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); + input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); + + input_report_key(wdata->extension.input, BTN_START, bp); + input_report_key(wdata->extension.input, BTN_SELECT, bm); + + input_sync(wdata->extension.input); +} + +static int wiimod_drums_open(struct input_dev *dev) +{ + struct wiimote_data *wdata = input_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&wdata->state.lock, flags); + wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; + wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); + spin_unlock_irqrestore(&wdata->state.lock, flags); + + return 0; +} + +static void wiimod_drums_close(struct input_dev *dev) +{ + struct wiimote_data *wdata = input_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&wdata->state.lock, flags); + wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; + wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); + spin_unlock_irqrestore(&wdata->state.lock, flags); +} + +static int wiimod_drums_probe(const struct wiimod_ops *ops, + struct wiimote_data *wdata) +{ + int ret; + + wdata->extension.input = input_allocate_device(); + if (!wdata->extension.input) + return -ENOMEM; + + input_set_drvdata(wdata->extension.input, wdata); + wdata->extension.input->open = wiimod_drums_open; + wdata->extension.input->close = wiimod_drums_close; + wdata->extension.input->dev.parent = &wdata->hdev->dev; + wdata->extension.input->id.bustype = wdata->hdev->bus; + wdata->extension.input->id.vendor = wdata->hdev->vendor; + wdata->extension.input->id.product = wdata->hdev->product; + wdata->extension.input->id.version = wdata->hdev->version; + wdata->extension.input->name = WIIMOTE_NAME " Drums"; + + set_bit(EV_KEY, wdata->extension.input->evbit); + set_bit(BTN_START, wdata->extension.input->keybit); + set_bit(BTN_SELECT, wdata->extension.input->keybit); + + set_bit(EV_ABS, wdata->extension.input->evbit); + set_bit(ABS_X, wdata->extension.input->absbit); + set_bit(ABS_Y, wdata->extension.input->absbit); + set_bit(ABS_HAT0X, wdata->extension.input->absbit); + set_bit(ABS_HAT0Y, wdata->extension.input->absbit); + set_bit(ABS_HAT1X, wdata->extension.input->absbit); + set_bit(ABS_HAT2X, wdata->extension.input->absbit); + set_bit(ABS_HAT2Y, wdata->extension.input->absbit); + set_bit(ABS_HAT3X, wdata->extension.input->absbit); + set_bit(ABS_HAT3Y, wdata->extension.input->absbit); + input_set_abs_params(wdata->extension.input, + ABS_X, -32, 31, 1, 1); + input_set_abs_params(wdata->extension.input, + ABS_Y, -32, 31, 1, 1); + input_set_abs_params(wdata->extension.input, + ABS_HAT0X, 0, 7, 0, 0); + input_set_abs_params(wdata->extension.input, + ABS_HAT0Y, 0, 7, 0, 0); + input_set_abs_params(wdata->extension.input, + ABS_HAT1X, 0, 7, 0, 0); + input_set_abs_params(wdata->extension.input, + ABS_HAT2X, 0, 7, 0, 0); + input_set_abs_params(wdata->extension.input, + ABS_HAT2Y, 0, 7, 0, 0); + input_set_abs_params(wdata->extension.input, + ABS_HAT3X, 0, 7, 0, 0); + input_set_abs_params(wdata->extension.input, + ABS_HAT3Y, 0, 7, 0, 0); + + ret = input_register_device(wdata->extension.input); + if (ret) + goto err_free; + + return 0; + +err_free: + input_free_device(wdata->extension.input); + wdata->extension.input = NULL; + return ret; +} + +static void wiimod_drums_remove(const struct wiimod_ops *ops, + struct wiimote_data *wdata) +{ + if (!wdata->extension.input) + return; + + input_unregister_device(wdata->extension.input); + wdata->extension.input = NULL; +} + +static const struct wiimod_ops wiimod_drums = { + .flags = 0, + .arg = 0, + .probe = wiimod_drums_probe, + .remove = wiimod_drums_remove, + .in_ext = wiimod_drums_in_ext, +}; + +/* + * Guitar + * Guitar-Hero, Rock-Band and other games came bundled with guitars which can + * be plugged as extension to a Wiimote. + * We create a separate device for guitars and report all information via this + * input device. + */ + +enum wiimod_guitar_keys { + WIIMOD_GUITAR_KEY_G, + WIIMOD_GUITAR_KEY_R, + WIIMOD_GUITAR_KEY_Y, + WIIMOD_GUITAR_KEY_B, + WIIMOD_GUITAR_KEY_O, + WIIMOD_GUITAR_KEY_UP, + WIIMOD_GUITAR_KEY_DOWN, + WIIMOD_GUITAR_KEY_PLUS, + WIIMOD_GUITAR_KEY_MINUS, + WIIMOD_GUITAR_KEY_NUM, +}; + +static const __u16 wiimod_guitar_map[] = { + BTN_1, /* WIIMOD_GUITAR_KEY_G */ + BTN_2, /* WIIMOD_GUITAR_KEY_R */ + BTN_3, /* WIIMOD_GUITAR_KEY_Y */ + BTN_4, /* WIIMOD_GUITAR_KEY_B */ + BTN_5, /* WIIMOD_GUITAR_KEY_O */ + BTN_DPAD_UP, /* WIIMOD_GUITAR_KEY_UP */ + BTN_DPAD_DOWN, /* WIIMOD_GUITAR_KEY_DOWN */ + BTN_START, /* WIIMOD_GUITAR_KEY_PLUS */ + BTN_SELECT, /* WIIMOD_GUITAR_KEY_MINUS */ +}; + +static void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext) +{ + __u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu; + + /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 1 | 0 | 0 | SX <5:0> | + * 2 | 0 | 0 | SY <5:0> | + * -----+-----+-----+-----+-----------------------------+ + * 3 | 0 | 0 | 0 | TB <4:0> | + * -----+-----+-----+-----+-----------------------------+ + * 4 | 0 | 0 | 0 | WB <4:0> | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 | 1 | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 6 | BO | BR | BB | BG | BY | 1 | 1 | BU | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * All buttons are 0 if pressed + * + * With Motion+ enabled, it will look like this: + * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 1 | 0 | 0 | SX <5:1> | BU | + * 2 | 0 | 0 | SY <5:1> | 1 | + * -----+-----+-----+-----+-----------------------+-----+ + * 3 | 0 | 0 | 0 | TB <4:0> | + * -----+-----+-----+-----+-----------------------------+ + * 4 | 0 | 0 | 0 | WB <4:0> | + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 5 | 1 | BD | 1 | B- | 1 | B+ | 1 |XXXXX| + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + * 6 | BO | BR | BB | BG | BY | 1 |XXXXX|XXXXX| + * -----+-----+-----+-----+-----+-----+-----+-----+-----+ + */ + + sx = ext[0] & 0x3f; + sy = ext[1] & 0x3f; + tb = ext[2] & 0x1f; + wb = ext[3] & 0x1f; + bd = !(ext[4] & 0x40); + bm = !(ext[4] & 0x10); + bp = !(ext[4] & 0x04); + bo = !(ext[5] & 0x80); + br = !(ext[5] & 0x40); + bb = !(ext[5] & 0x20); + bg = !(ext[5] & 0x10); + by = !(ext[5] & 0x08); + bu = !(ext[5] & 0x01); + + if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) { + bu = !(ext[0] & 0x01); + sx &= 0x3e; + sy &= 0x3e; + } + + input_report_abs(wdata->extension.input, ABS_X, sx - 0x20); + input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20); + input_report_abs(wdata->extension.input, ABS_HAT0X, tb); + input_report_abs(wdata->extension.input, ABS_HAT1X, wb - 0x10); + + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_G], + bg); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_R], + br); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_Y], + by); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_B], + bb); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_O], + bo); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_UP], + bu); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_DOWN], + bd); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_PLUS], + bp); + input_report_key(wdata->extension.input, + wiimod_guitar_map[WIIMOD_GUITAR_KEY_MINUS], + bm); + + input_sync(wdata->extension.input); +} + +static int wiimod_guitar_open(struct input_dev *dev) +{ + struct wiimote_data *wdata = input_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&wdata->state.lock, flags); + wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; + wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); + spin_unlock_irqrestore(&wdata->state.lock, flags); + + return 0; +} + +static void wiimod_guitar_close(struct input_dev *dev) +{ + struct wiimote_data *wdata = input_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&wdata->state.lock, flags); + wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; + wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); + spin_unlock_irqrestore(&wdata->state.lock, flags); +} + +static int wiimod_guitar_probe(const struct wiimod_ops *ops, + struct wiimote_data *wdata) +{ + int ret, i; + + wdata->extension.input = input_allocate_device(); + if (!wdata->extension.input) + return -ENOMEM; + + input_set_drvdata(wdata->extension.input, wdata); + wdata->extension.input->open = wiimod_guitar_open; + wdata->extension.input->close = wiimod_guitar_close; + wdata->extension.input->dev.parent = &wdata->hdev->dev; + wdata->extension.input->id.bustype = wdata->hdev->bus; + wdata->extension.input->id.vendor = wdata->hdev->vendor; + wdata->extension.input->id.product = wdata->hdev->product; + wdata->extension.input->id.version = wdata->hdev->version; + wdata->extension.input->name = WIIMOTE_NAME " Guitar"; + + set_bit(EV_KEY, wdata->extension.input->evbit); + for (i = 0; i < WIIMOD_GUITAR_KEY_NUM; ++i) + set_bit(wiimod_guitar_map[i], + wdata->extension.input->keybit); + + set_bit(EV_ABS, wdata->extension.input->evbit); + set_bit(ABS_X, wdata->extension.input->absbit); + set_bit(ABS_Y, wdata->extension.input->absbit); + set_bit(ABS_HAT0X, wdata->extension.input->absbit); + set_bit(ABS_HAT1X, wdata->extension.input->absbit); + input_set_abs_params(wdata->extension.input, + ABS_X, -32, 31, 1, 1); + input_set_abs_params(wdata->extension.input, + ABS_Y, -32, 31, 1, 1); + input_set_abs_params(wdata->extension.input, + ABS_HAT0X, 0, 0x1f, 1, 1); + input_set_abs_params(wdata->extension.input, + ABS_HAT1X, 0, 0x0f, 1, 1); + + ret = input_register_device(wdata->extension.input); + if (ret) + goto err_free; + + return 0; + +err_free: + input_free_device(wdata->extension.input); + wdata->extension.input = NULL; + return ret; +} + +static void wiimod_guitar_remove(const struct wiimod_ops *ops, + struct wiimote_data *wdata) +{ + if (!wdata->extension.input) + return; + + input_unregister_device(wdata->extension.input); + wdata->extension.input = NULL; +} + +static const struct wiimod_ops wiimod_guitar = { + .flags = 0, + .arg = 0, + .probe = wiimod_guitar_probe, + .remove = wiimod_guitar_remove, + .in_ext = wiimod_guitar_in_ext, +}; + +/* * Builtin Motion Plus * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which * disables polling for Motion-Plus. This should be set only for devices which @@ -2201,4 +2639,6 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic, [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard, [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro, + [WIIMOTE_EXT_DRUMS] = &wiimod_drums, + [WIIMOTE_EXT_GUITAR] = &wiimod_guitar, }; diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h index 510ca77fe14e..3bf3d3cc1c38 100644 --- a/drivers/hid/hid-wiimote.h +++ b/drivers/hid/hid-wiimote.h @@ -89,6 +89,8 @@ enum wiimote_exttype { WIIMOTE_EXT_CLASSIC_CONTROLLER, WIIMOTE_EXT_BALANCE_BOARD, WIIMOTE_EXT_PRO_CONTROLLER, + WIIMOTE_EXT_DRUMS, + WIIMOTE_EXT_GUITAR, WIIMOTE_EXT_NUM, }; @@ -137,6 +139,7 @@ struct wiimote_state { /* calibration/cache data */ __u16 calib_bboard[4][3]; __s16 calib_pro_sticks[4]; + __u8 pressure_drums[7]; __u8 cache_rumble; }; diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index eae0cb3ddec6..2ce194a84868 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1002,18 +1002,18 @@ static int i2c_hid_probe(struct i2c_client *client, return client->irq; } - ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL); + ihid = devm_kzalloc(&client->dev, sizeof(*ihid), GFP_KERNEL); if (!ihid) return -ENOMEM; if (client->dev.of_node) { ret = i2c_hid_of_probe(client, &ihid->pdata); if (ret) - goto err; + return ret; } else if (!platform_data) { ret = i2c_hid_acpi_pdata(client, &ihid->pdata); if (ret) - goto err; + return ret; } else { ihid->pdata = *platform_data; } @@ -1021,21 +1021,20 @@ static int i2c_hid_probe(struct i2c_client *client, /* Parse platform agnostic common properties from ACPI / device tree */ i2c_hid_fwnode_probe(client, &ihid->pdata); - ihid->pdata.supply = devm_regulator_get(&client->dev, "vdd"); - if (IS_ERR(ihid->pdata.supply)) { - ret = PTR_ERR(ihid->pdata.supply); - if (ret != -EPROBE_DEFER) - dev_err(&client->dev, "Failed to get regulator: %d\n", - ret); - goto err; - } + ihid->pdata.supplies[0].supply = "vdd"; + ihid->pdata.supplies[1].supply = "vddl"; + + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(ihid->pdata.supplies), + ihid->pdata.supplies); + if (ret) + return ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ihid->pdata.supplies), + ihid->pdata.supplies); + if (ret < 0) + return ret; - ret = regulator_enable(ihid->pdata.supply); - if (ret < 0) { - dev_err(&client->dev, "Failed to enable regulator: %d\n", - ret); - goto err; - } if (ihid->pdata.post_power_delay_ms) msleep(ihid->pdata.post_power_delay_ms); @@ -1122,11 +1121,9 @@ err_pm: pm_runtime_disable(&client->dev); err_regulator: - regulator_disable(ihid->pdata.supply); - -err: + regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies), + ihid->pdata.supplies); i2c_hid_free_buffers(ihid); - kfree(ihid); return ret; } @@ -1148,9 +1145,8 @@ static int i2c_hid_remove(struct i2c_client *client) if (ihid->bufsize) i2c_hid_free_buffers(ihid); - regulator_disable(ihid->pdata.supply); - - kfree(ihid); + regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies), + ihid->pdata.supplies); return 0; } @@ -1201,9 +1197,8 @@ static int i2c_hid_suspend(struct device *dev) hid_warn(hid, "Failed to enable irq wake: %d\n", wake_status); } else { - ret = regulator_disable(ihid->pdata.supply); - if (ret < 0) - hid_warn(hid, "Failed to disable supply: %d\n", ret); + regulator_bulk_disable(ARRAY_SIZE(ihid->pdata.supplies), + ihid->pdata.supplies); } return 0; @@ -1218,9 +1213,11 @@ static int i2c_hid_resume(struct device *dev) int wake_status; if (!device_may_wakeup(&client->dev)) { - ret = regulator_enable(ihid->pdata.supply); - if (ret < 0) - hid_warn(hid, "Failed to enable supply: %d\n", ret); + ret = regulator_bulk_enable(ARRAY_SIZE(ihid->pdata.supplies), + ihid->pdata.supplies); + if (ret) + hid_warn(hid, "Failed to enable supplies: %d\n", ret); + if (ihid->pdata.post_power_delay_ms) msleep(ihid->pdata.post_power_delay_ms); } else if (ihid->irq_wake_enabled) { diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 9a60ec13cb10..bfbca7ec54ce 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -907,8 +907,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) struct ishtp_device *dev; int i; - dev = kzalloc(sizeof(struct ishtp_device) + sizeof(struct ish_hw), - GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, + sizeof(struct ishtp_device) + sizeof(struct ish_hw), + GFP_KERNEL); if (!dev) return NULL; @@ -925,7 +926,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) for (i = 0; i < IPC_TX_FIFO_SIZE; ++i) { struct wr_msg_ctl_info *tx_buf; - tx_buf = kzalloc(sizeof(struct wr_msg_ctl_info), GFP_KERNEL); + tx_buf = devm_kzalloc(&pdev->dev, + sizeof(struct wr_msg_ctl_info), + GFP_KERNEL); if (!tx_buf) { /* * IPC buffers may be limited or not available diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index a2c53ea3b5ed..050f9872f5c0 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -95,6 +95,13 @@ static int ish_init(struct ishtp_device *dev) return 0; } +static const struct pci_device_id ish_invalid_pci_ids[] = { + /* Mehlow platform special pci ids */ + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xA309)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xA30A)}, + {} +}; + /** * ish_probe() - PCI driver probe callback * @pdev: pci device @@ -110,6 +117,10 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct ish_hw *hw; int ret; + /* Check for invalid platforms for ISH support */ + if (pci_dev_present(ish_invalid_pci_ids)) + return -ENODEV; + /* enable pci dev */ ret = pci_enable_device(pdev); if (ret) { @@ -172,7 +183,6 @@ free_irq: free_irq(pdev->irq, dev); free_device: pci_iounmap(pdev, hw->mem_addr); - kfree(dev); release_regions: pci_release_regions(pdev); disable_device: @@ -202,7 +212,6 @@ static void ish_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_clear_master(pdev); pci_disable_device(pdev); - kfree(ishtp_dev); } static struct device __maybe_unused *ish_resume_device; diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.c b/drivers/hid/intel-ish-hid/ishtp/hbm.c index ae4a69f7f2f4..8b5dd580ceec 100644 --- a/drivers/hid/intel-ish-hid/ishtp/hbm.c +++ b/drivers/hid/intel-ish-hid/ishtp/hbm.c @@ -298,7 +298,6 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr = &hdr; const size_t len = sizeof(struct hbm_flow_control); int rv; - unsigned int num_frags; unsigned long flags; spin_lock_irqsave(&cl->fc_spinlock, flags); @@ -314,7 +313,6 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev, return 0; } - num_frags = cl->recv_msg_num_frags; cl->recv_msg_num_frags = 0; rv = ishtp_write_message(dev, ishtp_hdr, data); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index af0e0d061b15..11103efebbaa 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -480,6 +480,7 @@ static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; struct usbhid_device *usbhid = hid->driver_data; + unsigned long flags; int unplug = 0, status = urb->status; switch (status) { @@ -501,7 +502,7 @@ static void hid_ctrl(struct urb *urb) hid_warn(urb->dev, "ctrl urb status %d received\n", status); } - spin_lock(&usbhid->lock); + spin_lock_irqsave(&usbhid->lock, flags); if (unplug) { usbhid->ctrltail = usbhid->ctrlhead; @@ -511,13 +512,13 @@ static void hid_ctrl(struct urb *urb) if (usbhid->ctrlhead != usbhid->ctrltail && hid_submit_ctrl(hid) == 0) { /* Successfully submitted next urb in queue */ - spin_unlock(&usbhid->lock); + spin_unlock_irqrestore(&usbhid->lock, flags); return; } } clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); - spin_unlock(&usbhid->lock); + spin_unlock_irqrestore(&usbhid->lock, flags); usb_autopm_put_interface_async(usbhid->intf); wake_up(&usbhid->wait); } diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index d6797535fff9..0bdd85d486fe 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -210,6 +210,57 @@ static int wacom_calc_hid_res(int logical_extents, int physical_extents, return hidinput_calc_abs_res(&field, ABS_X); } +static void wacom_hid_usage_quirk(struct hid_device *hdev, + struct hid_field *field, struct hid_usage *usage) +{ + struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_features *features = &wacom->wacom_wac.features; + unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); + + /* + * The Dell Canvas 27 needs to be switched to its vendor-defined + * report to provide the best resolution. + */ + if (hdev->vendor == USB_VENDOR_ID_WACOM && + hdev->product == 0x4200 && + field->application == HID_UP_MSVENDOR) { + wacom->wacom_wac.mode_report = field->report->id; + wacom->wacom_wac.mode_value = 2; + } + + /* + * ISDv4 devices which predate HID's adoption of the + * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its + * position instead. We can accurately detect if a + * usage with that value should be HID_DG_BARRELSWITCH2 + * based on the surrounding usages, which have remained + * constant across generations. + */ + if (features->type == HID_GENERIC && + usage->hid == 0x000D0000 && + field->application == HID_DG_PEN && + field->physical == HID_DG_STYLUS) { + int i = usage->usage_index; + + if (i-4 >= 0 && i+1 < field->maxusage && + field->usage[i-4].hid == HID_DG_TIPSWITCH && + field->usage[i-3].hid == HID_DG_BARRELSWITCH && + field->usage[i-2].hid == HID_DG_ERASER && + field->usage[i-1].hid == HID_DG_INVERT && + field->usage[i+1].hid == HID_DG_INRANGE) { + usage->hid = HID_DG_BARRELSWITCH2; + } + } + + /* 2nd-generation Intuos Pro Large has incorrect Y maximum */ + if (hdev->vendor == USB_VENDOR_ID_WACOM && + hdev->product == 0x0358 && + WACOM_PEN_FIELD(field) && + equivalent_usage == HID_GD_Y) { + field->logical_maximum = 43200; + } +} + static void wacom_feature_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { @@ -221,6 +272,8 @@ static void wacom_feature_mapping(struct hid_device *hdev, int ret; u32 n; + wacom_hid_usage_quirk(hdev, field, usage); + switch (equivalent_usage) { case HID_DG_CONTACTMAX: /* leave touch_max as is if predefined */ @@ -300,13 +353,6 @@ static void wacom_feature_mapping(struct hid_device *hdev, kfree(data); break; } - - if (hdev->vendor == USB_VENDOR_ID_WACOM && - hdev->product == 0x4200 /* Dell Canvas 27 */ && - field->application == HID_UP_MSVENDOR) { - wacom->wacom_wac.mode_report = field->report->id; - wacom->wacom_wac.mode_value = 2; - } } /* @@ -348,6 +394,7 @@ static void wacom_usage_mapping(struct hid_device *hdev, struct wacom_features *features = &wacom->wacom_wac.features; bool finger = WACOM_FINGER_FIELD(field); bool pen = WACOM_PEN_FIELD(field); + unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); /* * Requiring Stylus Usage will ignore boot mouse @@ -361,49 +408,9 @@ static void wacom_usage_mapping(struct hid_device *hdev, else return; - /* - * Bamboo models do not support HID_DG_CONTACTMAX. - * And, Bamboo Pen only descriptor contains touch. - */ - if (features->type > BAMBOO_PT) { - /* ISDv4 touch devices at least supports one touch point */ - if (finger && !features->touch_max) - features->touch_max = 1; - } - - /* - * ISDv4 devices which predate HID's adoption of the - * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its - * position instead. We can accurately detect if a - * usage with that value should be HID_DG_BARRELSWITCH2 - * based on the surrounding usages, which have remained - * constant across generations. - */ - if (features->type == HID_GENERIC && - usage->hid == 0x000D0000 && - field->application == HID_DG_PEN && - field->physical == HID_DG_STYLUS) { - int i = usage->usage_index; + wacom_hid_usage_quirk(hdev, field, usage); - if (i-4 >= 0 && i+1 < field->maxusage && - field->usage[i-4].hid == HID_DG_TIPSWITCH && - field->usage[i-3].hid == HID_DG_BARRELSWITCH && - field->usage[i-2].hid == HID_DG_ERASER && - field->usage[i-1].hid == HID_DG_INVERT && - field->usage[i+1].hid == HID_DG_INRANGE) { - usage->hid = HID_DG_BARRELSWITCH2; - } - } - - /* 2nd-generation Intuos Pro Large has incorrect Y maximum */ - if (hdev->vendor == USB_VENDOR_ID_WACOM && - hdev->product == 0x0358 && - WACOM_PEN_FIELD(field) && - wacom_equivalent_usage(usage->hid) == HID_GD_Y) { - field->logical_maximum = 43200; - } - - switch (usage->hid) { + switch (equivalent_usage) { case HID_GD_X: features->x_max = field->logical_maximum; if (finger) { @@ -703,18 +710,6 @@ struct wacom_hdev_data { static LIST_HEAD(wacom_udev_list); static DEFINE_MUTEX(wacom_udev_list_lock); -static bool compare_device_paths(struct hid_device *hdev_a, - struct hid_device *hdev_b, char separator) -{ - int n1 = strrchr(hdev_a->phys, separator) - hdev_a->phys; - int n2 = strrchr(hdev_b->phys, separator) - hdev_b->phys; - - if (n1 != n2 || n1 <= 0 || n2 <= 0) - return false; - - return !strncmp(hdev_a->phys, hdev_b->phys, n1); -} - static bool wacom_are_sibling(struct hid_device *hdev, struct hid_device *sibling) { @@ -737,10 +732,10 @@ static bool wacom_are_sibling(struct hid_device *hdev, * the same physical parent device path. */ if (hdev->vendor == sibling->vendor && hdev->product == sibling->product) { - if (!compare_device_paths(hdev, sibling, '/')) + if (!hid_compare_device_paths(hdev, sibling, '/')) return false; } else { - if (!compare_device_paths(hdev, sibling, '.')) + if (!hid_compare_device_paths(hdev, sibling, '.')) return false; } @@ -787,7 +782,7 @@ static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev) /* Try to find an already-probed interface from the same device */ list_for_each_entry(data, &wacom_udev_list, list) { - if (compare_device_paths(hdev, data->dev, '/')) { + if (hid_compare_device_paths(hdev, data->dev, '/')) { kref_get(&data->kref); return data; } diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index ad7afa74d365..e0a06be5ef5c 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -4357,19 +4357,19 @@ static const struct wacom_features wacom_features_0x5E = .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x90 = { "Wacom ISDv4 90", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ static const struct wacom_features wacom_features_0x93 = { "Wacom ISDv4 93", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; static const struct wacom_features wacom_features_0x97 = { "Wacom ISDv4 97", 26202, 16325, 511, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ static const struct wacom_features wacom_features_0x9A = { "Wacom ISDv4 9A", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; static const struct wacom_features wacom_features_0x9F = { "Wacom ISDv4 9F", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; static const struct wacom_features wacom_features_0xE2 = { "Wacom ISDv4 E2", 26202, 16325, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; @@ -4384,13 +4384,13 @@ static const struct wacom_features wacom_features_0xE6 = TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; static const struct wacom_features wacom_features_0xEC = { "Wacom ISDv4 EC", 25710, 14500, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ static const struct wacom_features wacom_features_0xED = { "Wacom ISDv4 ED", 26202, 16325, 255, 0, - TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; static const struct wacom_features wacom_features_0xEF = { "Wacom ISDv4 EF", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ static const struct wacom_features wacom_features_0x100 = { "Wacom ISDv4 100", 26202, 16325, 255, 0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -4408,10 +4408,10 @@ static const struct wacom_features wacom_features_0x10F = MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x116 = { "Wacom ISDv4 116", 26202, 16325, 255, 0, - TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; static const struct wacom_features wacom_features_0x12C = { "Wacom ISDv4 12C", 27848, 15752, 2047, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ static const struct wacom_features wacom_features_0x4001 = { "Wacom ISDv4 4001", 26202, 16325, 255, 0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ccf42663a908..81da17a42dc9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1320,6 +1320,16 @@ config SENSORS_PWM_FAN This driver can also be built as a module. If so, the module will be called pwm-fan. +config SENSORS_RASPBERRYPI_HWMON + tristate "Raspberry Pi voltage monitor" + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + If you say yes here you get support for voltage sensor on the + Raspberry Pi. + + This driver can also be built as a module. If so, the module + will be called raspberrypi-hwmon. + config SENSORS_SHT15 tristate "Sensiron humidity and temperature sensors. SHT15 and compat." depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 842c92f83ce6..93f7f41ea4ad 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -143,6 +143,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o +obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c new file mode 100644 index 000000000000..fb4e4a6bb1f6 --- /dev/null +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Raspberry Pi voltage sensor driver + * + * Based on firmware/raspberrypi.c by Noralf Trønnes + * + * Copyright (C) 2018 Stefan Wahren <stefan.wahren@i2se.com> + */ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + +#define UNDERVOLTAGE_STICKY_BIT BIT(16) + +struct rpi_hwmon_data { + struct device *hwmon_dev; + struct rpi_firmware *fw; + u32 last_throttled; + struct delayed_work get_values_poll_work; +}; + +static void rpi_firmware_get_throttled(struct rpi_hwmon_data *data) +{ + u32 new_uv, old_uv, value; + int ret; + + /* Request firmware to clear sticky bits */ + value = 0xffff; + + ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED, + &value, sizeof(value)); + if (ret) { + dev_err_once(data->hwmon_dev, "Failed to get throttled (%d)\n", + ret); + return; + } + + new_uv = value & UNDERVOLTAGE_STICKY_BIT; + old_uv = data->last_throttled & UNDERVOLTAGE_STICKY_BIT; + data->last_throttled = value; + + if (new_uv == old_uv) + return; + + if (new_uv) + dev_crit(data->hwmon_dev, "Undervoltage detected!\n"); + else + dev_info(data->hwmon_dev, "Voltage normalised\n"); + + sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm"); +} + +static void get_values_poll(struct work_struct *work) +{ + struct rpi_hwmon_data *data; + + data = container_of(work, struct rpi_hwmon_data, + get_values_poll_work.work); + + rpi_firmware_get_throttled(data); + + /* + * We can't run faster than the sticky shift (100ms) since we get + * flipping in the sticky bits that are cleared. + */ + schedule_delayed_work(&data->get_values_poll_work, 2 * HZ); +} + +static int rpi_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct rpi_hwmon_data *data = dev_get_drvdata(dev); + + *val = !!(data->last_throttled & UNDERVOLTAGE_STICKY_BIT); + return 0; +} + +static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return 0444; +} + +static const u32 rpi_in_config[] = { + HWMON_I_LCRIT_ALARM, + 0 +}; + +static const struct hwmon_channel_info rpi_in = { + .type = hwmon_in, + .config = rpi_in_config, +}; + +static const struct hwmon_channel_info *rpi_info[] = { + &rpi_in, + NULL +}; + +static const struct hwmon_ops rpi_hwmon_ops = { + .is_visible = rpi_is_visible, + .read = rpi_read, +}; + +static const struct hwmon_chip_info rpi_chip_info = { + .ops = &rpi_hwmon_ops, + .info = rpi_info, +}; + +static int rpi_hwmon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rpi_hwmon_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* Parent driver assure that firmware is correct */ + data->fw = dev_get_drvdata(dev->parent); + + /* Init throttled */ + ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED, + &data->last_throttled, + sizeof(data->last_throttled)); + + data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "rpi_volt", + data, + &rpi_chip_info, + NULL); + + INIT_DELAYED_WORK(&data->get_values_poll_work, get_values_poll); + platform_set_drvdata(pdev, data); + + if (!PTR_ERR_OR_ZERO(data->hwmon_dev)) + schedule_delayed_work(&data->get_values_poll_work, 2 * HZ); + + return PTR_ERR_OR_ZERO(data->hwmon_dev); +} + +static int rpi_hwmon_remove(struct platform_device *pdev) +{ + struct rpi_hwmon_data *data = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&data->get_values_poll_work); + + return 0; +} + +static struct platform_driver rpi_hwmon_driver = { + .probe = rpi_hwmon_probe, + .remove = rpi_hwmon_remove, + .driver = { + .name = "raspberrypi-hwmon", + }, +}; +module_platform_driver(rpi_hwmon_driver); + +MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); +MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 634f58042c77..d293e55553bd 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -1182,7 +1182,7 @@ static void msc_mmap_close(struct vm_area_struct *vma) mutex_unlock(&msc->buf_mutex); } -static int msc_mmap_fault(struct vm_fault *vmf) +static vm_fault_t msc_mmap_fault(struct vm_fault *vmf) { struct msc_iter *iter = vmf->vma->vm_file->private_data; struct msc *msc = iter->msc; diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 72c94c60fdd1..bed6ba63c983 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -18,4 +18,3 @@ obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG -CFLAGS_i2c-core-base.o := -Wno-deprecated-declarations diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4f8df2ec87b1..451d4ae50e66 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -116,24 +116,21 @@ config I2C_I801 DH89xxCC (PCH) Panther Point (PCH) Lynx Point (PCH) - Lynx Point-LP (PCH) Avoton (SOC) Wellsburg (PCH) Coleto Creek (PCH) Wildcat Point (PCH) - Wildcat Point-LP (PCH) BayTrail (SOC) Braswell (SOC) - Sunrise Point-H (PCH) - Sunrise Point-LP (PCH) - Kaby Lake-H (PCH) + Sunrise Point (PCH) + Kaby Lake (PCH) DNV (SOC) Broxton (SOC) Lewisburg (PCH) Gemini Lake (SOC) - Cannon Lake-H (PCH) - Cannon Lake-LP (PCH) + Cannon Lake (PCH) Cedar Fork (PCH) + Ice Lake (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -762,6 +759,13 @@ config I2C_OMAP Like OMAP1510/1610/1710/5912 and OMAP242x. For details see http://www.ti.com/omap. +config I2C_OWL + tristate "Actions Semiconductor Owl I2C Controller" + depends on ARCH_ACTIONS || COMPILE_TEST + help + Say Y here if you want to use the I2C bus controller on + the Actions Semiconductor Owl SoC's. + config I2C_PASEMI tristate "PA Semi SMBus interface" depends on PPC_PASEMI && PCI @@ -828,6 +832,19 @@ config I2C_PXA_SLAVE is necessary for systems where the PXA may be a target on the I2C bus. +config I2C_QCOM_GENI + tristate "Qualcomm Technologies Inc.'s GENI based I2C controller" + depends on ARCH_QCOM || COMPILE_TEST + depends on QCOM_GENI_SE + help + This driver supports GENI serial engine based I2C controller in + master mode on the Qualcomm Technologies Inc.'s SoCs. If you say + yes to this option, support will be included for the built-in I2C + interface on the Qualcomm Technologies Inc.'s SoCs. + + This driver can also be built as a module. If so, the module + will be called i2c-qcom-geni. + config I2C_QUP tristate "Qualcomm QUP based I2C controller" depends on ARCH_QCOM @@ -1330,4 +1347,15 @@ config I2C_ZX2967 This driver can also be built as a module. If so, the module will be called i2c-zx2967. +config I2C_FSI + tristate "FSI I2C driver" + depends on FSI + help + Driver for FSI bus attached I2C masters. These are I2C masters that + are connected to the system over an FSI bus, instead of the more + common PCI or MMIO interface. + + This driver can also be built as a module. If so, the module will be + called as i2c-fsi. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 5a869144a0c5..18b26af82b1c 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_I2C_MXS) += i2c-mxs.o obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o +obj-$(CONFIG_I2C_OWL) += i2c-owl.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o @@ -83,6 +84,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o +obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o @@ -137,5 +139,6 @@ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o +obj-$(CONFIG_I2C_FSI) += i2c-fsi.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 95a80a8f81b5..134567f3019f 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -384,6 +384,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, if (status) return status; len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); + /* fall through */ case I2C_SMBUS_I2C_BLOCK_DATA: for (i = 0; i < len; i++) { status = amd_ec_read(smbus, AMD_SMB_DATA + i, diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 60e4d0e939a3..a4f956c6d567 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -111,22 +111,22 @@ #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) enum aspeed_i2c_master_state { + ASPEED_I2C_MASTER_INACTIVE, ASPEED_I2C_MASTER_START, ASPEED_I2C_MASTER_TX_FIRST, ASPEED_I2C_MASTER_TX, ASPEED_I2C_MASTER_RX_FIRST, ASPEED_I2C_MASTER_RX, ASPEED_I2C_MASTER_STOP, - ASPEED_I2C_MASTER_INACTIVE, }; enum aspeed_i2c_slave_state { + ASPEED_I2C_SLAVE_STOP, ASPEED_I2C_SLAVE_START, ASPEED_I2C_SLAVE_READ_REQUESTED, ASPEED_I2C_SLAVE_READ_PROCESSED, ASPEED_I2C_SLAVE_WRITE_REQUESTED, ASPEED_I2C_SLAVE_WRITE_RECEIVED, - ASPEED_I2C_SLAVE_STOP, }; struct aspeed_i2c_bus { @@ -234,7 +234,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus) bool irq_handled = true; u8 value; - spin_lock(&bus->lock); if (!slave) { irq_handled = false; goto out; @@ -325,7 +324,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus) writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG); out: - spin_unlock(&bus->lock); return irq_handled; } #endif /* CONFIG_I2C_SLAVE */ @@ -389,7 +387,6 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) u8 recv_byte; int ret; - spin_lock(&bus->lock); irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG); /* Ack all interrupt bits. */ writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG); @@ -407,7 +404,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) */ ret = aspeed_i2c_is_irq_error(irq_status); if (ret < 0) { - dev_dbg(bus->dev, "received error interrupt: 0x%08x", + dev_dbg(bus->dev, "received error interrupt: 0x%08x\n", irq_status); bus->cmd_err = ret; bus->master_state = ASPEED_I2C_MASTER_INACTIVE; @@ -416,7 +413,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) /* We are in an invalid state; reset bus to a known state. */ if (!bus->msgs) { - dev_err(bus->dev, "bus in unknown state"); + dev_err(bus->dev, "bus in unknown state\n"); bus->cmd_err = -EIO; if (bus->master_state != ASPEED_I2C_MASTER_STOP) aspeed_i2c_do_stop(bus); @@ -431,7 +428,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) */ if (bus->master_state == ASPEED_I2C_MASTER_START) { if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { - pr_devel("no slave present at %02x", msg->addr); + pr_devel("no slave present at %02x\n", msg->addr); status_ack |= ASPEED_I2CD_INTR_TX_NAK; bus->cmd_err = -ENXIO; aspeed_i2c_do_stop(bus); @@ -451,11 +448,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) switch (bus->master_state) { case ASPEED_I2C_MASTER_TX: if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) { - dev_dbg(bus->dev, "slave NACKed TX"); + dev_dbg(bus->dev, "slave NACKed TX\n"); status_ack |= ASPEED_I2CD_INTR_TX_NAK; goto error_and_stop; } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) { - dev_err(bus->dev, "slave failed to ACK TX"); + dev_err(bus->dev, "slave failed to ACK TX\n"); goto error_and_stop; } status_ack |= ASPEED_I2CD_INTR_TX_ACK; @@ -478,7 +475,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) /* fallthrough intended */ case ASPEED_I2C_MASTER_RX: if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) { - dev_err(bus->dev, "master failed to RX"); + dev_err(bus->dev, "master failed to RX\n"); goto error_and_stop; } status_ack |= ASPEED_I2CD_INTR_RX_DONE; @@ -509,7 +506,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) goto out_no_complete; case ASPEED_I2C_MASTER_STOP: if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) { - dev_err(bus->dev, "master failed to STOP"); + dev_err(bus->dev, "master failed to STOP\n"); bus->cmd_err = -EIO; /* Do not STOP as we have already tried. */ } else { @@ -520,7 +517,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus) goto out_complete; case ASPEED_I2C_MASTER_INACTIVE: dev_err(bus->dev, - "master received interrupt 0x%08x, but is inactive", + "master received interrupt 0x%08x, but is inactive\n", irq_status); bus->cmd_err = -EIO; /* Do not STOP as we should be inactive. */ @@ -547,22 +544,29 @@ out_no_complete: dev_err(bus->dev, "irq handled != irq. expected 0x%08x, but was 0x%08x\n", irq_status, status_ack); - spin_unlock(&bus->lock); return !!irq_status; } static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) { struct aspeed_i2c_bus *bus = dev_id; + bool ret; + + spin_lock(&bus->lock); #if IS_ENABLED(CONFIG_I2C_SLAVE) if (aspeed_i2c_slave_irq(bus)) { dev_dbg(bus->dev, "irq handled by slave.\n"); - return IRQ_HANDLED; + ret = true; + goto out; } #endif /* CONFIG_I2C_SLAVE */ - return aspeed_i2c_master_irq(bus) ? IRQ_HANDLED : IRQ_NONE; + ret = aspeed_i2c_master_irq(bus); + +out: + spin_unlock(&bus->lock); + return ret ? IRQ_HANDLED : IRQ_NONE; } static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, @@ -851,7 +855,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL); if (IS_ERR(bus->rst)) { dev_err(&pdev->dev, - "missing or invalid reset controller device tree entry"); + "missing or invalid reset controller device tree entry\n"); return PTR_ERR(bus->rst); } reset_control_deassert(bus->rst); @@ -868,7 +872,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) if (!match) bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val; else - bus->get_clk_reg_val = match->data; + bus->get_clk_reg_val = (u32 (*)(u32))match->data; /* Initialize the I2C adapter */ spin_lock_init(&bus->lock); diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 78792b4d6437..826d32049996 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -689,9 +689,9 @@ static int brcmstb_i2c_suspend(struct device *dev) { struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); - i2c_lock_adapter(&i2c_dev->adapter); + i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); i2c_dev->is_suspended = true; - i2c_unlock_adapter(&i2c_dev->adapter); + i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); return 0; } @@ -700,10 +700,10 @@ static int brcmstb_i2c_resume(struct device *dev) { struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); - i2c_lock_adapter(&i2c_dev->adapter); + i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); brcmstb_i2c_set_bsc_reg_defaults(i2c_dev); i2c_dev->is_suspended = false; - i2c_unlock_adapter(&i2c_dev->adapter); + i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER); return 0; } diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 7379043711df..11caafa0e050 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -718,14 +718,14 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb, dev = container_of(nb, struct davinci_i2c_dev, freq_transition); - i2c_lock_adapter(&dev->adapter); + i2c_lock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER); if (val == CPUFREQ_PRECHANGE) { davinci_i2c_reset_ctrl(dev, 0); } else if (val == CPUFREQ_POSTCHANGE) { i2c_davinci_calc_clk_dividers(dev); davinci_i2c_reset_ctrl(dev, 1); } - i2c_unlock_adapter(&dev->adapter); + i2c_unlock_bus(&dev->adapter, I2C_LOCK_ROOT_ADAPTER); return 0; } diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index dbda8c9c8a1c..a2a275cfc1f6 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Intel BayTrail PMIC I2C bus semaphore implementaion * Copyright (c) 2014, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include <linux/delay.h> #include <linux/device.h> diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 48914dfc8ce8..69ec4a791f23 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Synopsys DesignWare I2C adapter driver. * @@ -6,20 +7,6 @@ * Copyright (C) 2006 Texas Instruments. * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - * */ #include <linux/clk.h> #include <linux/delay.h> @@ -31,6 +18,7 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/swab.h> #include "i2c-designware-core.h" @@ -94,6 +82,40 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) } } +/** + * i2c_dw_set_reg_access() - Set register access flags + * @dev: device private data + * + * Autodetects needed register access mode and sets access flags accordingly. + * This must be called before doing any other register access. + */ +int i2c_dw_set_reg_access(struct dw_i2c_dev *dev) +{ + u32 reg; + int ret; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + reg = dw_readl(dev, DW_IC_COMP_TYPE); + i2c_dw_release_lock(dev); + + if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) { + /* Configure register endianess access */ + dev->flags |= ACCESS_SWAP; + } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) { + /* Configure register access mode 16bit */ + dev->flags |= ACCESS_16BIT; + } else if (reg != DW_IC_COMP_TYPE_VALUE) { + dev_err(dev->dev, + "Unknown Synopsys component type: 0x%08x\n", reg); + return -ENODEV; + } + + return 0; +} + u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) { /* @@ -149,6 +171,47 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset; } +int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) +{ + u32 reg; + int ret; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + /* Configure SDA Hold Time if required */ + reg = dw_readl(dev, DW_IC_COMP_VERSION); + if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { + if (!dev->sda_hold_time) { + /* Keep previous hold time setting if no one set it */ + dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); + } + + /* + * Workaround for avoiding TX arbitration lost in case I2C + * slave pulls SDA down "too quickly" after falling egde of + * SCL by enabling non-zero SDA RX hold. Specification says it + * extends incoming SDA low to high transition while SCL is + * high but it apprears to help also above issue. + */ + if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) + dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; + + dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n", + dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK, + dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT); + } else if (dev->sda_hold_time) { + dev_warn(dev->dev, + "Hardware too old to adjust SDA hold time.\n"); + dev->sda_hold_time = 0; + } + + i2c_dw_release_lock(dev); + + return 0; +} + void __i2c_dw_disable(struct dw_i2c_dev *dev) { int timeout = 100; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index d690e648bc01..e367b1af4ab2 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Synopsys DesignWare I2C adapter driver. * @@ -6,20 +7,6 @@ * Copyright (C) 2006 Texas Instruments. * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - * */ #include <linux/i2c.h> @@ -212,7 +199,8 @@ * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo * @rx_outstanding: current master-rx elements in tx fifo - * @clk_freq: bus clock frequency + * @timings: bus clock frequency, SDA hold and other timings + * @sda_hold_time: SDA hold value * @ss_hcnt: standard speed HCNT value * @ss_lcnt: standard speed LCNT value * @fs_hcnt: fast speed HCNT value @@ -264,10 +252,8 @@ struct dw_i2c_dev { unsigned int tx_fifo_depth; unsigned int rx_fifo_depth; int rx_outstanding; - u32 clk_freq; + struct i2c_timings timings; u32 sda_hold_time; - u32 sda_falling_time; - u32 scl_falling_time; u16 ss_hcnt; u16 ss_lcnt; u16 fs_hcnt; @@ -295,8 +281,10 @@ struct dw_i2c_dev { u32 dw_readl(struct dw_i2c_dev *dev, int offset); void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); +int i2c_dw_set_reg_access(struct dw_i2c_dev *dev); u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); +int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 27436a937492..e18442b9973a 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Synopsys DesignWare I2C adapter driver (master only). * @@ -6,20 +7,6 @@ * Copyright (C) 2006 Texas Instruments. * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - * */ #include <linux/delay.h> #include <linux/err.h> @@ -45,90 +32,79 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev) dw_writel(dev, dev->master_cfg, DW_IC_CON); } -/** - * i2c_dw_init() - Initialize the designware I2C master hardware - * @dev: device private data - * - * This functions configures and enables the I2C master. - * This function is called during I2C init function, and in case of timeout at - * run time. - */ -static int i2c_dw_init_master(struct dw_i2c_dev *dev) +static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) { - u32 hcnt, lcnt; - u32 reg, comp_param1; + u32 ic_clk = i2c_dw_clk_rate(dev); + const char *mode_str, *fp_str = ""; + u32 comp_param1; u32 sda_falling_time, scl_falling_time; + struct i2c_timings *t = &dev->timings; int ret; ret = i2c_dw_acquire_lock(dev); if (ret) return ret; - - reg = dw_readl(dev, DW_IC_COMP_TYPE); - if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { - /* Configure register endianess access */ - dev->flags |= ACCESS_SWAP; - } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) { - /* Configure register access mode 16bit */ - dev->flags |= ACCESS_16BIT; - } else if (reg != DW_IC_COMP_TYPE_VALUE) { - dev_err(dev->dev, - "Unknown Synopsys component type: 0x%08x\n", reg); - i2c_dw_release_lock(dev); - return -ENODEV; - } - comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); + i2c_dw_release_lock(dev); - /* Disable the adapter */ - __i2c_dw_disable(dev); - - /* Set standard and fast speed deviders for high/low periods */ - - sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ - scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ + /* Set standard and fast speed dividers for high/low periods */ + sda_falling_time = t->sda_fall_ns ?: 300; /* ns */ + scl_falling_time = t->scl_fall_ns ?: 300; /* ns */ - /* Set SCL timing parameters for standard-mode */ - if (dev->ss_hcnt && dev->ss_lcnt) { - hcnt = dev->ss_hcnt; - lcnt = dev->ss_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), + /* Calculate SCL timing parameters for standard mode if not set */ + if (!dev->ss_hcnt || !dev->ss_lcnt) { + dev->ss_hcnt = + i2c_dw_scl_hcnt(ic_clk, 4000, /* tHD;STA = tHIGH = 4.0 us */ sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), + dev->ss_lcnt = + i2c_dw_scl_lcnt(ic_clk, 4700, /* tLOW = 4.7 us */ scl_falling_time, 0); /* No offset */ } - dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); - dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - - /* Set SCL timing parameters for fast-mode or fast-mode plus */ - if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { - hcnt = dev->fp_hcnt; - lcnt = dev->fp_lcnt; - } else if (dev->fs_hcnt && dev->fs_lcnt) { - hcnt = dev->fs_hcnt; - lcnt = dev->fs_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), + dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n", + dev->ss_hcnt, dev->ss_lcnt); + + /* + * Set SCL timing parameters for fast mode or fast mode plus. Only + * difference is the timing parameter values since the registers are + * the same. + */ + if (t->bus_freq_hz == 1000000) { + /* + * Check are fast mode plus parameters available and use + * fast mode if not. + */ + if (dev->fp_hcnt && dev->fp_lcnt) { + dev->fs_hcnt = dev->fp_hcnt; + dev->fs_lcnt = dev->fp_lcnt; + fp_str = " Plus"; + } + } + /* + * Calculate SCL timing parameters for fast mode if not set. They are + * needed also in high speed mode. + */ + if (!dev->fs_hcnt || !dev->fs_lcnt) { + dev->fs_hcnt = + i2c_dw_scl_hcnt(ic_clk, 600, /* tHD;STA = tHIGH = 0.6 us */ sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), + dev->fs_lcnt = + i2c_dw_scl_lcnt(ic_clk, 1300, /* tLOW = 1.3 us */ scl_falling_time, 0); /* No offset */ } - dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); - dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); + dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n", + fp_str, dev->fs_hcnt, dev->fs_lcnt); + /* Check is high speed possible and fall back to fast mode if not */ if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) == DW_IC_CON_SPEED_HIGH) { if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) @@ -136,37 +112,70 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) dev_err(dev->dev, "High Speed not supported!\n"); dev->master_cfg &= ~DW_IC_CON_SPEED_MASK; dev->master_cfg |= DW_IC_CON_SPEED_FAST; + dev->hs_hcnt = 0; + dev->hs_lcnt = 0; } else if (dev->hs_hcnt && dev->hs_lcnt) { - hcnt = dev->hs_hcnt; - lcnt = dev->hs_lcnt; - dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); - dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", - hcnt, lcnt); + dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n", + dev->hs_hcnt, dev->hs_lcnt); } } - /* Configure SDA Hold Time if required */ - reg = dw_readl(dev, DW_IC_COMP_VERSION); - if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { - if (!dev->sda_hold_time) { - /* Keep previous hold time setting if no one set it */ - dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); - } - /* - * Workaround for avoiding TX arbitration lost in case I2C - * slave pulls SDA down "too quickly" after falling egde of - * SCL by enabling non-zero SDA RX hold. Specification says it - * extends incoming SDA low to high transition while SCL is - * high but it apprears to help also above issue. - */ - if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) - dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; - dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); - } else if (dev->sda_hold_time) { - dev_warn(dev->dev, - "Hardware too old to adjust SDA hold time.\n"); + ret = i2c_dw_set_sda_hold(dev); + if (ret) + goto out; + + switch (dev->master_cfg & DW_IC_CON_SPEED_MASK) { + case DW_IC_CON_SPEED_STD: + mode_str = "Standard Mode"; + break; + case DW_IC_CON_SPEED_HIGH: + mode_str = "High Speed Mode"; + break; + default: + mode_str = "Fast Mode"; } + dev_dbg(dev->dev, "Bus speed: %s%s\n", mode_str, fp_str); + +out: + return ret; +} + +/** + * i2c_dw_init() - Initialize the designware I2C master hardware + * @dev: device private data + * + * This functions configures and enables the I2C master. + * This function is called during I2C init function, and in case of timeout at + * run time. + */ +static int i2c_dw_init_master(struct dw_i2c_dev *dev) +{ + int ret; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + /* Disable the adapter */ + __i2c_dw_disable(dev); + + /* Write standard speed timing parameters */ + dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT); + dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT); + + /* Write fast mode/fast mode plus timing parameters */ + dw_writel(dev, dev->fs_hcnt, DW_IC_FS_SCL_HCNT); + dw_writel(dev, dev->fs_lcnt, DW_IC_FS_SCL_LCNT); + + /* Write high speed timing parameters if supported */ + if (dev->hs_hcnt && dev->hs_lcnt) { + dw_writel(dev, dev->hs_hcnt, DW_IC_HS_SCL_HCNT); + dw_writel(dev, dev->hs_lcnt, DW_IC_HS_SCL_LCNT); + } + + /* Write SDA hold time if supported */ + if (dev->sda_hold_time) + dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); i2c_dw_configure_fifo_master(dev); i2c_dw_release_lock(dev); @@ -253,13 +262,6 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) break; } - if (msgs[dev->msg_write_idx].len == 0) { - dev_err(dev->dev, - "%s: invalid message length\n", __func__); - dev->msg_err = -EINVAL; - break; - } - if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { /* new i2c_msg */ buf = msgs[dev->msg_write_idx].buf; @@ -502,6 +504,10 @@ static const struct i2c_algorithm i2c_dw_algo = { .functionality = i2c_dw_func, }; +static const struct i2c_adapter_quirks i2c_dw_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { u32 stat; @@ -681,6 +687,14 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) dev->disable = i2c_dw_disable; dev->disable_int = i2c_dw_disable_int; + ret = i2c_dw_set_reg_access(dev); + if (ret) + return ret; + + ret = i2c_dw_set_timings_master(dev); + if (ret) + return ret; + ret = dev->init(dev); if (ret) return ret; @@ -689,6 +703,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) "Synopsys DesignWare I2C adapter"); adap->retries = 3; adap->algo = &i2c_dw_algo; + adap->quirks = &i2c_dw_quirks; adap->dev.parent = dev->dev; i2c_set_adapdata(adap, dev); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 86e1bd0b82e9..d50f80487214 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Synopsys DesignWare I2C adapter driver (master only). * @@ -7,22 +8,7 @@ * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2011, 2015, 2016 Intel Corporation. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - * */ - #include <linux/acpi.h> #include <linux/delay.h> #include <linux/err.h> @@ -105,6 +91,7 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) case 0x0817: c->bus_cfg &= ~DW_IC_CON_SPEED_MASK; c->bus_cfg |= DW_IC_CON_SPEED_STD; + /* fall through */ case 0x0818: case 0x0819: c->bus_num = pdev->device - 0x817 + 3; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 5660daf6c92e..1a8d2da5b000 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Synopsys DesignWare I2C adapter driver. * @@ -6,20 +7,6 @@ * Copyright (C) 2006 Texas Instruments. * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - * */ #include <linux/acpi.h> #include <linux/clk-provider.h> @@ -96,6 +83,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], static int dw_i2c_acpi_configure(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + struct i2c_timings *t = &dev->timings; u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0; acpi_handle handle = ACPI_HANDLE(&pdev->dev); const struct acpi_device_id *id; @@ -115,7 +103,7 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht); dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht); - switch (dev->clk_freq) { + switch (t->bus_freq_hz) { case 100000: dev->sda_hold_time = ss_ht; break; @@ -175,6 +163,8 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) static void i2c_dw_configure_master(struct dw_i2c_dev *dev) { + struct i2c_timings *t = &dev->timings; + dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY; dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | @@ -182,7 +172,7 @@ static void i2c_dw_configure_master(struct dw_i2c_dev *dev) dev->mode = DW_IC_MASTER; - switch (dev->clk_freq) { + switch (t->bus_freq_hz) { case 100000: dev->master_cfg |= DW_IC_CON_SPEED_STD; break; @@ -240,7 +230,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); struct i2c_adapter *adap; struct dw_i2c_dev *dev; - u32 acpi_speed, ht = 0; + struct i2c_timings *t; + u32 acpi_speed; struct resource *mem; int i, irq, ret; static const int supported_speeds[] = { @@ -272,18 +263,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) reset_control_deassert(dev->rst); } - if (pdata) { - dev->clk_freq = pdata->i2c_scl_freq; - } else { - device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns", - &ht); - device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns", - &dev->sda_falling_time); - device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns", - &dev->scl_falling_time); - device_property_read_u32(&pdev->dev, "clock-frequency", - &dev->clk_freq); - } + t = &dev->timings; + if (pdata) + t->bus_freq_hz = pdata->i2c_scl_freq; + else + i2c_parse_fw_timings(&pdev->dev, t, false); acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev); /* @@ -300,12 +284,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) * Find bus speed from the "clock-frequency" device property, ACPI * or by using fast mode if neither is set. */ - if (acpi_speed && dev->clk_freq) - dev->clk_freq = min(dev->clk_freq, acpi_speed); - else if (acpi_speed || dev->clk_freq) - dev->clk_freq = max(dev->clk_freq, acpi_speed); + if (acpi_speed && t->bus_freq_hz) + t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed); + else if (acpi_speed || t->bus_freq_hz) + t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed); else - dev->clk_freq = 400000; + t->bus_freq_hz = 400000; if (has_acpi_companion(&pdev->dev)) dw_i2c_acpi_configure(pdev); @@ -314,11 +298,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) * Only standard mode at 100kHz, fast mode at 400kHz, * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported. */ - if (dev->clk_freq != 100000 && dev->clk_freq != 400000 - && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) { + if (t->bus_freq_hz != 100000 && t->bus_freq_hz != 400000 && + t->bus_freq_hz != 1000000 && t->bus_freq_hz != 3400000) { dev_err(&pdev->dev, "%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n", - dev->clk_freq); + t->bus_freq_hz); ret = -EINVAL; goto exit_reset; } @@ -334,12 +318,14 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) dev->clk = devm_clk_get(&pdev->dev, NULL); if (!i2c_dw_prepare_clk(dev, true)) { + u64 clk_khz; + dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; + clk_khz = dev->get_clk_rate_khz(dev); - if (!dev->sda_hold_time && ht) - dev->sda_hold_time = div_u64( - (u64)dev->get_clk_rate_khz(dev) * ht + 500000, - 1000000); + if (!dev->sda_hold_time && t->sda_hold_ns) + dev->sda_hold_time = + div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000); } dw_i2c_set_fifo_size(dev, pdev->id); diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index 8ce2cd368477..e7f9305b2dd9 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Synopsys DesignWare I2C adapter driver (slave only). * * Based on the Synopsys DesignWare I2C adapter driver (master). * * Copyright (C) 2016 Synopsys Inc. - * - * ---------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * ---------------------------------------------------------------------------- - * */ #include <linux/delay.h> #include <linux/err.h> @@ -51,53 +38,18 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) */ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) { - u32 reg, comp_param1; int ret; ret = i2c_dw_acquire_lock(dev); if (ret) return ret; - reg = dw_readl(dev, DW_IC_COMP_TYPE); - if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { - /* Configure register endianness access. */ - dev->flags |= ACCESS_SWAP; - } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) { - /* Configure register access mode 16bit. */ - dev->flags |= ACCESS_16BIT; - } else if (reg != DW_IC_COMP_TYPE_VALUE) { - dev_err(dev->dev, - "Unknown Synopsys component type: 0x%08x\n", reg); - i2c_dw_release_lock(dev); - return -ENODEV; - } - - comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); - /* Disable the adapter. */ __i2c_dw_disable(dev); - /* Configure SDA Hold Time if required. */ - reg = dw_readl(dev, DW_IC_COMP_VERSION); - if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { - if (!dev->sda_hold_time) { - /* Keep previous hold time setting if no one set it. */ - dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); - } - /* - * Workaround for avoiding TX arbitration lost in case I2C - * slave pulls SDA down "too quickly" after falling egde of - * SCL by enabling non-zero SDA RX hold. Specification says it - * extends incoming SDA low to high transition while SCL is - * high but it apprears to help also above issue. - */ - if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) - dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; + /* Write SDA hold time if supported */ + if (dev->sda_hold_time) dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); - } else { - dev_warn(dev->dev, - "Hardware too old to adjust SDA hold time.\n"); - } i2c_dw_configure_fifo_slave(dev); i2c_dw_release_lock(dev); @@ -299,6 +251,14 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) dev->disable = i2c_dw_disable; dev->disable_int = i2c_dw_disable_int; + ret = i2c_dw_set_reg_access(dev); + if (ret) + return ret; + + ret = i2c_dw_set_sda_hold(dev); + if (ret) + return ret; + ret = dev->init(dev); if (ret) return ret; diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index ba9b6ea48a31..35b302d983e0 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * I2C driver for the Renesas EMEV2 SoC * * Copyright (C) 2015 Wolfram Sang <wsa@sang-engineering.com> * Copyright 2013 Codethink Ltd. * Copyright 2010-2015 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index de82ad8ff534..c1ce2299a76e 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -176,7 +176,10 @@ #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100)) -#define HSI2C_EXYNOS7 BIT(0) +enum i2c_type_exynos { + I2C_TYPE_EXYNOS5, + I2C_TYPE_EXYNOS7, +}; struct exynos5_i2c { struct i2c_adapter adap; @@ -212,27 +215,30 @@ struct exynos5_i2c { /** * struct exynos_hsi2c_variant - platform specific HSI2C driver data * @fifo_depth: the fifo depth supported by the HSI2C module + * @hw: the hardware variant of Exynos I2C controller * * Specifies platform specific configuration of HSI2C module. * Note: A structure for driver specific platform data is used for future * expansion of its usage. */ struct exynos_hsi2c_variant { - unsigned int fifo_depth; - unsigned int hw; + unsigned int fifo_depth; + enum i2c_type_exynos hw; }; static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { .fifo_depth = 64, + .hw = I2C_TYPE_EXYNOS5, }; static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { .fifo_depth = 16, + .hw = I2C_TYPE_EXYNOS5, }; static const struct exynos_hsi2c_variant exynos7_hsi2c_data = { .fifo_depth = 16, - .hw = HSI2C_EXYNOS7, + .hw = I2C_TYPE_EXYNOS7, }; static const struct of_device_id exynos5_i2c_match[] = { @@ -300,7 +306,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) */ t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; temp = clkin / op_clk - 8 - t_ftl_cycle; - if (i2c->variant->hw != HSI2C_EXYNOS7) + if (i2c->variant->hw != I2C_TYPE_EXYNOS7) temp -= t_ftl_cycle; div = temp / 512; clk_cycle = temp / (div + 1) - 2; @@ -424,7 +430,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) writel(int_status, i2c->regs + HSI2C_INT_STATUS); /* handle interrupt related to the transfer status */ - if (i2c->variant->hw == HSI2C_EXYNOS7) { + if (i2c->variant->hw == I2C_TYPE_EXYNOS7) { if (int_status & HSI2C_INT_TRANS_DONE) { i2c->trans_done = 1; i2c->state = 0; @@ -571,7 +577,7 @@ static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c) { unsigned long timeout; - if (i2c->variant->hw != HSI2C_EXYNOS7) + if (i2c->variant->hw != I2C_TYPE_EXYNOS7) return; /* @@ -612,7 +618,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) unsigned long flags; unsigned short trig_lvl; - if (i2c->variant->hw == HSI2C_EXYNOS7) + if (i2c->variant->hw == I2C_TYPE_EXYNOS7) int_en |= HSI2C_INT_I2C_TRANS; else int_en |= HSI2C_INT_I2C; diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c new file mode 100644 index 000000000000..1e2be2219a60 --- /dev/null +++ b/drivers/i2c/busses/i2c-fsi.c @@ -0,0 +1,752 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * FSI-attached I2C master algorithm + * + * Copyright 2018 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/fsi.h> +#include <linux/i2c.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/slab.h> + +#define FSI_ENGID_I2C 0x7 + +#define I2C_DEFAULT_CLK_DIV 6 + +/* i2c registers */ +#define I2C_FSI_FIFO 0x00 +#define I2C_FSI_CMD 0x04 +#define I2C_FSI_MODE 0x08 +#define I2C_FSI_WATER_MARK 0x0C +#define I2C_FSI_INT_MASK 0x10 +#define I2C_FSI_INT_COND 0x14 +#define I2C_FSI_OR_INT_MASK 0x14 +#define I2C_FSI_INTS 0x18 +#define I2C_FSI_AND_INT_MASK 0x18 +#define I2C_FSI_STAT 0x1C +#define I2C_FSI_RESET_I2C 0x1C +#define I2C_FSI_ESTAT 0x20 +#define I2C_FSI_RESET_ERR 0x20 +#define I2C_FSI_RESID_LEN 0x24 +#define I2C_FSI_SET_SCL 0x24 +#define I2C_FSI_PORT_BUSY 0x28 +#define I2C_FSI_RESET_SCL 0x2C +#define I2C_FSI_SET_SDA 0x30 +#define I2C_FSI_RESET_SDA 0x34 + +/* cmd register */ +#define I2C_CMD_WITH_START BIT(31) +#define I2C_CMD_WITH_ADDR BIT(30) +#define I2C_CMD_RD_CONT BIT(29) +#define I2C_CMD_WITH_STOP BIT(28) +#define I2C_CMD_FORCELAUNCH BIT(27) +#define I2C_CMD_ADDR GENMASK(23, 17) +#define I2C_CMD_READ BIT(16) +#define I2C_CMD_LEN GENMASK(15, 0) + +/* mode register */ +#define I2C_MODE_CLKDIV GENMASK(31, 16) +#define I2C_MODE_PORT GENMASK(15, 10) +#define I2C_MODE_ENHANCED BIT(3) +#define I2C_MODE_DIAG BIT(2) +#define I2C_MODE_PACE_ALLOW BIT(1) +#define I2C_MODE_WRAP BIT(0) + +/* watermark register */ +#define I2C_WATERMARK_HI GENMASK(15, 12) +#define I2C_WATERMARK_LO GENMASK(7, 4) + +#define I2C_FIFO_HI_LVL 4 +#define I2C_FIFO_LO_LVL 4 + +/* interrupt register */ +#define I2C_INT_INV_CMD BIT(15) +#define I2C_INT_PARITY BIT(14) +#define I2C_INT_BE_OVERRUN BIT(13) +#define I2C_INT_BE_ACCESS BIT(12) +#define I2C_INT_LOST_ARB BIT(11) +#define I2C_INT_NACK BIT(10) +#define I2C_INT_DAT_REQ BIT(9) +#define I2C_INT_CMD_COMP BIT(8) +#define I2C_INT_STOP_ERR BIT(7) +#define I2C_INT_BUSY BIT(6) +#define I2C_INT_IDLE BIT(5) + +/* status register */ +#define I2C_STAT_INV_CMD BIT(31) +#define I2C_STAT_PARITY BIT(30) +#define I2C_STAT_BE_OVERRUN BIT(29) +#define I2C_STAT_BE_ACCESS BIT(28) +#define I2C_STAT_LOST_ARB BIT(27) +#define I2C_STAT_NACK BIT(26) +#define I2C_STAT_DAT_REQ BIT(25) +#define I2C_STAT_CMD_COMP BIT(24) +#define I2C_STAT_STOP_ERR BIT(23) +#define I2C_STAT_MAX_PORT GENMASK(19, 16) +#define I2C_STAT_ANY_INT BIT(15) +#define I2C_STAT_SCL_IN BIT(11) +#define I2C_STAT_SDA_IN BIT(10) +#define I2C_STAT_PORT_BUSY BIT(9) +#define I2C_STAT_SELF_BUSY BIT(8) +#define I2C_STAT_FIFO_COUNT GENMASK(7, 0) + +#define I2C_STAT_ERR (I2C_STAT_INV_CMD | \ + I2C_STAT_PARITY | \ + I2C_STAT_BE_OVERRUN | \ + I2C_STAT_BE_ACCESS | \ + I2C_STAT_LOST_ARB | \ + I2C_STAT_NACK | \ + I2C_STAT_STOP_ERR) +#define I2C_STAT_ANY_RESP (I2C_STAT_ERR | \ + I2C_STAT_DAT_REQ | \ + I2C_STAT_CMD_COMP) + +/* extended status register */ +#define I2C_ESTAT_FIFO_SZ GENMASK(31, 24) +#define I2C_ESTAT_SCL_IN_SY BIT(15) +#define I2C_ESTAT_SDA_IN_SY BIT(14) +#define I2C_ESTAT_S_SCL BIT(13) +#define I2C_ESTAT_S_SDA BIT(12) +#define I2C_ESTAT_M_SCL BIT(11) +#define I2C_ESTAT_M_SDA BIT(10) +#define I2C_ESTAT_HI_WATER BIT(9) +#define I2C_ESTAT_LO_WATER BIT(8) +#define I2C_ESTAT_PORT_BUSY BIT(7) +#define I2C_ESTAT_SELF_BUSY BIT(6) +#define I2C_ESTAT_VERSION GENMASK(4, 0) + +/* port busy register */ +#define I2C_PORT_BUSY_RESET BIT(31) + +/* wait for command complete or data request */ +#define I2C_CMD_SLEEP_MAX_US 500 +#define I2C_CMD_SLEEP_MIN_US 50 + +/* wait after reset; choose time from legacy driver */ +#define I2C_RESET_SLEEP_MAX_US 2000 +#define I2C_RESET_SLEEP_MIN_US 1000 + +/* choose timeout length from legacy driver; it's well tested */ +#define I2C_ABORT_TIMEOUT msecs_to_jiffies(100) + +struct fsi_i2c_master { + struct fsi_device *fsi; + u8 fifo_size; + struct list_head ports; + struct mutex lock; +}; + +struct fsi_i2c_port { + struct list_head list; + struct i2c_adapter adapter; + struct fsi_i2c_master *master; + u16 port; + u16 xfrd; +}; + +static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg, + u32 *data) +{ + int rc; + __be32 data_be; + + rc = fsi_device_read(fsi, reg, &data_be, sizeof(data_be)); + if (rc) + return rc; + + *data = be32_to_cpu(data_be); + + return 0; +} + +static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg, + u32 *data) +{ + __be32 data_be = cpu_to_be32p(data); + + return fsi_device_write(fsi, reg, &data_be, sizeof(data_be)); +} + +static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c) +{ + int rc; + u32 mode = I2C_MODE_ENHANCED, extended_status, watermark; + u32 interrupt = 0; + + /* since we use polling, disable interrupts */ + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_INT_MASK, &interrupt); + if (rc) + return rc; + + mode |= FIELD_PREP(I2C_MODE_CLKDIV, I2C_DEFAULT_CLK_DIV); + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); + if (rc) + return rc; + + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &extended_status); + if (rc) + return rc; + + i2c->fifo_size = FIELD_GET(I2C_ESTAT_FIFO_SZ, extended_status); + watermark = FIELD_PREP(I2C_WATERMARK_HI, + i2c->fifo_size - I2C_FIFO_HI_LVL); + watermark |= FIELD_PREP(I2C_WATERMARK_LO, I2C_FIFO_LO_LVL); + + return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_WATER_MARK, &watermark); +} + +static int fsi_i2c_set_port(struct fsi_i2c_port *port) +{ + int rc; + struct fsi_device *fsi = port->master->fsi; + u32 mode, dummy = 0; + + rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode); + if (rc) + return rc; + + if (FIELD_GET(I2C_MODE_PORT, mode) == port->port) + return 0; + + mode = (mode & ~I2C_MODE_PORT) | FIELD_PREP(I2C_MODE_PORT, port->port); + rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode); + if (rc) + return rc; + + /* reset engine when port is changed */ + return fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy); +} + +static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg, + bool stop) +{ + struct fsi_i2c_master *i2c = port->master; + u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR; + + port->xfrd = 0; + + if (msg->flags & I2C_M_RD) + cmd |= I2C_CMD_READ; + + if (stop || msg->flags & I2C_M_STOP) + cmd |= I2C_CMD_WITH_STOP; + + cmd |= FIELD_PREP(I2C_CMD_ADDR, msg->addr); + cmd |= FIELD_PREP(I2C_CMD_LEN, msg->len); + + return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_CMD, &cmd); +} + +static int fsi_i2c_get_op_bytes(int op_bytes) +{ + /* fsi is limited to max 4 byte aligned ops */ + if (op_bytes > 4) + return 4; + else if (op_bytes == 3) + return 2; + return op_bytes; +} + +static int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, + u8 fifo_count) +{ + int write; + int rc; + struct fsi_i2c_master *i2c = port->master; + int bytes_to_write = i2c->fifo_size - fifo_count; + int bytes_remaining = msg->len - port->xfrd; + + bytes_to_write = min(bytes_to_write, bytes_remaining); + + while (bytes_to_write) { + write = fsi_i2c_get_op_bytes(bytes_to_write); + + rc = fsi_device_write(i2c->fsi, I2C_FSI_FIFO, + &msg->buf[port->xfrd], write); + if (rc) + return rc; + + port->xfrd += write; + bytes_to_write -= write; + } + + return 0; +} + +static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, + u8 fifo_count) +{ + int read; + int rc; + struct fsi_i2c_master *i2c = port->master; + int bytes_to_read; + int xfr_remaining = msg->len - port->xfrd; + u32 dummy; + + bytes_to_read = min_t(int, fifo_count, xfr_remaining); + + while (bytes_to_read) { + read = fsi_i2c_get_op_bytes(bytes_to_read); + + if (xfr_remaining) { + rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, + &msg->buf[port->xfrd], read); + if (rc) + return rc; + + port->xfrd += read; + xfr_remaining -= read; + } else { + /* no more buffer but data in fifo, need to clear it */ + rc = fsi_device_read(i2c->fsi, I2C_FSI_FIFO, &dummy, + read); + if (rc) + return rc; + } + + bytes_to_read -= read; + } + + return 0; +} + +static int fsi_i2c_get_scl(struct i2c_adapter *adap) +{ + u32 stat = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); + + return !!(stat & I2C_STAT_SCL_IN); +} + +static void fsi_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + u32 dummy = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + if (val) + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); + else + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy); +} + +static int fsi_i2c_get_sda(struct i2c_adapter *adap) +{ + u32 stat = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); + + return !!(stat & I2C_STAT_SDA_IN); +} + +static void fsi_i2c_set_sda(struct i2c_adapter *adap, int val) +{ + u32 dummy = 0; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + if (val) + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); + else + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy); +} + +static void fsi_i2c_prepare_recovery(struct i2c_adapter *adap) +{ + int rc; + u32 mode; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); + if (rc) + return; + + mode |= I2C_MODE_DIAG; + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +} + +static void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap) +{ + int rc; + u32 mode; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *i2c = port->master; + + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); + if (rc) + return; + + mode &= ~I2C_MODE_DIAG; + fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); +} + +static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c, + struct fsi_i2c_port *port) +{ + int rc; + u32 stat, dummy = 0; + + /* force bus reset, ignore errors */ + i2c_recover_bus(&port->adapter); + + /* reset errors */ + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy); + if (rc) + return rc; + + /* wait for command complete */ + usleep_range(I2C_RESET_SLEEP_MIN_US, I2C_RESET_SLEEP_MAX_US); + + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); + if (rc) + return rc; + + if (stat & I2C_STAT_CMD_COMP) + return 0; + + /* failed to get command complete; reset engine again */ + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); + if (rc) + return rc; + + /* re-init engine again */ + return fsi_i2c_dev_init(i2c); +} + +static int fsi_i2c_reset_engine(struct fsi_i2c_master *i2c, u16 port) +{ + int rc; + u32 mode, dummy = 0; + + /* reset engine */ + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy); + if (rc) + return rc; + + /* re-init engine */ + rc = fsi_i2c_dev_init(i2c); + if (rc) + return rc; + + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); + if (rc) + return rc; + + /* set port; default after reset is 0 */ + if (port) { + mode &= ~I2C_MODE_PORT; + mode |= FIELD_PREP(I2C_MODE_PORT, port); + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); + if (rc) + return rc; + } + + /* reset busy register; hw workaround */ + dummy = I2C_PORT_BUSY_RESET; + rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_PORT_BUSY, &dummy); + if (rc) + return rc; + + return 0; +} + +static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) +{ + int rc; + unsigned long start; + u32 cmd = I2C_CMD_WITH_STOP; + u32 stat; + struct fsi_i2c_master *i2c = port->master; + struct fsi_device *fsi = i2c->fsi; + + rc = fsi_i2c_reset_engine(i2c, port->port); + if (rc) + return rc; + + rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &stat); + if (rc) + return rc; + + /* if sda is low, peform full bus reset */ + if (!(stat & I2C_STAT_SDA_IN)) { + rc = fsi_i2c_reset_bus(i2c, port); + if (rc) + return rc; + } + + /* skip final stop command for these errors */ + if (status & (I2C_STAT_PARITY | I2C_STAT_LOST_ARB | I2C_STAT_STOP_ERR)) + return 0; + + /* write stop command */ + rc = fsi_i2c_write_reg(fsi, I2C_FSI_CMD, &cmd); + if (rc) + return rc; + + /* wait until we see command complete in the master */ + start = jiffies; + + do { + rc = fsi_i2c_read_reg(fsi, I2C_FSI_STAT, &status); + if (rc) + return rc; + + if (status & I2C_STAT_CMD_COMP) + return 0; + + usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US); + } while (time_after(start + I2C_ABORT_TIMEOUT, jiffies)); + + return -ETIMEDOUT; +} + +static int fsi_i2c_handle_status(struct fsi_i2c_port *port, + struct i2c_msg *msg, u32 status) +{ + int rc; + u8 fifo_count; + + if (status & I2C_STAT_ERR) { + rc = fsi_i2c_abort(port, status); + if (rc) + return rc; + + if (status & I2C_STAT_INV_CMD) + return -EINVAL; + + if (status & (I2C_STAT_PARITY | I2C_STAT_BE_OVERRUN | + I2C_STAT_BE_ACCESS)) + return -EPROTO; + + if (status & I2C_STAT_NACK) + return -ENXIO; + + if (status & I2C_STAT_LOST_ARB) + return -EAGAIN; + + if (status & I2C_STAT_STOP_ERR) + return -EBADMSG; + + return -EIO; + } + + if (status & I2C_STAT_DAT_REQ) { + fifo_count = FIELD_GET(I2C_STAT_FIFO_COUNT, status); + + if (msg->flags & I2C_M_RD) + return fsi_i2c_read_fifo(port, msg, fifo_count); + + return fsi_i2c_write_fifo(port, msg, fifo_count); + } + + if (status & I2C_STAT_CMD_COMP) { + if (port->xfrd < msg->len) + return -ENODATA; + + return msg->len; + } + + return 0; +} + +static int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg, + unsigned long timeout) +{ + u32 status = 0; + int rc; + unsigned long start = jiffies; + + do { + rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT, + &status); + if (rc) + return rc; + + if (status & I2C_STAT_ANY_RESP) { + rc = fsi_i2c_handle_status(port, msg, status); + if (rc < 0) + return rc; + + /* cmd complete and all data xfrd */ + if (rc == msg->len) + return 0; + + /* need to xfr more data, but maybe don't need wait */ + continue; + } + + usleep_range(I2C_CMD_SLEEP_MIN_US, I2C_CMD_SLEEP_MAX_US); + } while (time_after(start + timeout, jiffies)); + + return -ETIMEDOUT; +} + +static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int i, rc; + unsigned long start_time; + struct fsi_i2c_port *port = adap->algo_data; + struct fsi_i2c_master *master = port->master; + struct i2c_msg *msg; + + mutex_lock(&master->lock); + + rc = fsi_i2c_set_port(port); + if (rc) + goto unlock; + + for (i = 0; i < num; i++) { + msg = msgs + i; + start_time = jiffies; + + rc = fsi_i2c_start(port, msg, i == num - 1); + if (rc) + goto unlock; + + rc = fsi_i2c_wait(port, msg, + adap->timeout - (jiffies - start_time)); + if (rc) + goto unlock; + } + +unlock: + mutex_unlock(&master->lock); + return rc ? : num; +} + +static u32 fsi_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | + I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = { + .recover_bus = i2c_generic_scl_recovery, + .get_scl = fsi_i2c_get_scl, + .set_scl = fsi_i2c_set_scl, + .get_sda = fsi_i2c_get_sda, + .set_sda = fsi_i2c_set_sda, + .prepare_recovery = fsi_i2c_prepare_recovery, + .unprepare_recovery = fsi_i2c_unprepare_recovery, +}; + +static const struct i2c_algorithm fsi_i2c_algorithm = { + .master_xfer = fsi_i2c_xfer, + .functionality = fsi_i2c_functionality, +}; + +static int fsi_i2c_probe(struct device *dev) +{ + struct fsi_i2c_master *i2c; + struct fsi_i2c_port *port; + struct device_node *np; + int rc; + u32 port_no; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + mutex_init(&i2c->lock); + i2c->fsi = to_fsi_dev(dev); + INIT_LIST_HEAD(&i2c->ports); + + rc = fsi_i2c_dev_init(i2c); + if (rc) + return rc; + + /* Add adapter for each i2c port of the master. */ + for_each_available_child_of_node(dev->of_node, np) { + rc = of_property_read_u32(np, "reg", &port_no); + if (rc || port_no > USHRT_MAX) + continue; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + break; + + port->master = i2c; + port->port = port_no; + + port->adapter.owner = THIS_MODULE; + port->adapter.dev.of_node = np; + port->adapter.dev.parent = dev; + port->adapter.algo = &fsi_i2c_algorithm; + port->adapter.bus_recovery_info = &fsi_i2c_bus_recovery_info; + port->adapter.algo_data = port; + + snprintf(port->adapter.name, sizeof(port->adapter.name), + "i2c_bus-%u", port_no); + + rc = i2c_add_adapter(&port->adapter); + if (rc < 0) { + dev_err(dev, "Failed to register adapter: %d\n", rc); + kfree(port); + continue; + } + + list_add(&port->list, &i2c->ports); + } + + dev_set_drvdata(dev, i2c); + + return 0; +} + +static int fsi_i2c_remove(struct device *dev) +{ + struct fsi_i2c_master *i2c = dev_get_drvdata(dev); + struct fsi_i2c_port *port, *tmp; + + list_for_each_entry_safe(port, tmp, &i2c->ports, list) { + list_del(&port->list); + i2c_del_adapter(&port->adapter); + kfree(port); + } + + return 0; +} + +static const struct fsi_device_id fsi_i2c_ids[] = { + { FSI_ENGID_I2C, FSI_VERSION_ANY }, + { } +}; + +static struct fsi_driver fsi_i2c_driver = { + .id_table = fsi_i2c_ids, + .drv = { + .name = "i2c-fsi", + .bus = &fsi_bus_type, + .probe = fsi_i2c_probe, + .remove = fsi_i2c_remove, + }, +}; + +module_fsi_driver(fsi_i2c_driver); + +MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>"); +MODULE_DESCRIPTION("FSI attached I2C master"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 66f85bbf3591..c008d209f0b8 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -78,49 +78,43 @@ static struct dentry *i2c_gpio_debug_dir; #define getscl(bd) ((bd)->getscl((bd)->data)) #define WIRE_ATTRIBUTE(wire) \ -static int fops_##wire##_get(void *data, u64 *val) \ -{ \ - struct i2c_gpio_private_data *priv = data; \ - \ - i2c_lock_adapter(&priv->adap); \ - *val = get##wire(&priv->bit_data); \ - i2c_unlock_adapter(&priv->adap); \ - return 0; \ -} \ -static int fops_##wire##_set(void *data, u64 val) \ -{ \ - struct i2c_gpio_private_data *priv = data; \ - \ - i2c_lock_adapter(&priv->adap); \ - set##wire(&priv->bit_data, val); \ - i2c_unlock_adapter(&priv->adap); \ - return 0; \ -} \ +static int fops_##wire##_get(void *data, u64 *val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + *val = get##wire(&priv->bit_data); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ +static int fops_##wire##_set(void *data, u64 val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + set##wire(&priv->bit_data, val); \ + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); \ + return 0; \ +} \ DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") WIRE_ATTRIBUTE(scl); WIRE_ATTRIBUTE(sda); -static int fops_incomplete_transfer_set(void *data, u64 addr) +static void i2c_gpio_incomplete_transfer(struct i2c_gpio_private_data *priv, + u32 pattern, u8 pattern_size) { - struct i2c_gpio_private_data *priv = data; struct i2c_algo_bit_data *bit_data = &priv->bit_data; - int i, pattern; + int i; - if (addr > 0x7f) - return -EINVAL; - - /* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */ - pattern = (addr << 2) | 3; - - i2c_lock_adapter(&priv->adap); + i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); /* START condition */ setsda(bit_data, 0); udelay(bit_data->udelay); - /* Send ADDR+RD, request ACK, don't send STOP */ - for (i = 8; i >= 0; i--) { + /* Send pattern, request ACK, don't send STOP */ + for (i = pattern_size - 1; i >= 0; i--) { setscl(bit_data, 0); udelay(bit_data->udelay / 2); setsda(bit_data, (pattern >> i) & 1); @@ -129,11 +123,44 @@ static int fops_incomplete_transfer_set(void *data, u64 addr) udelay(bit_data->udelay); } - i2c_unlock_adapter(&priv->adap); + i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER); +} + +static int fops_incomplete_addr_phase_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + RD (1 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (addr << 2) | 3; + + i2c_gpio_incomplete_transfer(priv, pattern, 9); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_addr_phase, NULL, fops_incomplete_addr_phase_set, "%llu\n"); + +static int fops_incomplete_write_byte_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + u32 pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + WR (1 bit) + Client ACK (1 bit) */ + pattern = (addr << 2) | 1; + /* 0x00 (8 bit) + Client ACK, keep SDA hi (1 bit) */ + pattern = (pattern << 9) | 1; + + i2c_gpio_incomplete_transfer(priv, pattern, 18); return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n"); static void i2c_gpio_fault_injector_init(struct platform_device *pdev) { @@ -156,8 +183,10 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev) debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); - debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir, - priv, &fops_incomplete_transfer); + debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, + priv, &fops_incomplete_addr_phase); + debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, + priv, &fops_incomplete_write_byte); } static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 56dc69e7349f..ff340d7ae2e5 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas Solutions Highlander FPGA I2C/SMBus support. * @@ -6,10 +7,6 @@ * Copyright (C) 2008 Paul Mundt * Copyright (C) 2008 Renesas Solutions Corp. * Copyright (C) 2008 Atom Create Engineering Co., Ltd. - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file "COPYING" in the main directory - * of this archive for more details. */ #include <linux/module.h> #include <linux/interrupt.h> diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index aa726607645e..941c223f6491 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -70,6 +70,7 @@ * Cannon Lake-H (PCH) 0xa323 32 hard yes yes yes * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes * Cedar Fork (PCH) 0x18df 32 hard yes yes yes + * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -220,6 +221,7 @@ #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 #define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 +#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 @@ -1034,6 +1036,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, { 0, } }; @@ -1518,6 +1521,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) case PCI_DEVICE_ID_INTEL_CDF_SMBUS: case PCI_DEVICE_ID_INTEL_DNV_SMBUS: case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: + case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; priv->features |= FEATURE_SMBUS_PEC; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 498c5e891649..c406700789e1 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -421,10 +421,14 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) return -EAGAIN; } - if (for_busy && (temp & I2SR_IBB)) + if (for_busy && (temp & I2SR_IBB)) { + i2c_imx->stopped = 0; break; - if (!for_busy && !(temp & I2SR_IBB)) + } + if (!for_busy && !(temp & I2SR_IBB)) { + i2c_imx->stopped = 1; break; + } if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C bus is busy\n", __func__); @@ -538,7 +542,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) result = i2c_imx_bus_busy(i2c_imx, 1); if (result) return result; - i2c_imx->stopped = 0; temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK; temp &= ~I2CR_DMAEN; @@ -567,10 +570,8 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) udelay(i2c_imx->disable_delay); } - if (!i2c_imx->stopped) { + if (!i2c_imx->stopped) i2c_imx_bus_busy(i2c_imx, 0); - i2c_imx->stopped = 1; - } /* Disable I2C controller */ temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, @@ -668,9 +669,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp |= I2CR_DMAEN; - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); dma->chan_using = dma->chan_rx; dma->dma_transfer_dir = DMA_DEV_TO_MEM; @@ -727,7 +725,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); i2c_imx_bus_busy(i2c_imx, 0); - i2c_imx->stopped = 1; } else { /* * For i2c master receiver repeat restart operation like: @@ -783,6 +780,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo int i, result; unsigned int temp; int block_data = msgs->flags & I2C_M_RECV_LEN; + int use_dma = i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", @@ -809,12 +807,14 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo */ if ((msgs->len - 1) || block_data) temp &= ~I2CR_TXAK; + if (use_dma) + temp |= I2CR_DMAEN; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); - if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data) + if (use_dma) return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); /* read data */ @@ -850,7 +850,6 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); i2c_imx_bus_busy(i2c_imx, 0); - i2c_imx->stopped = 1; } else { /* * For i2c master receiver repeat restart operation like: diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 642c58946d8d..7d79317a1046 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -567,9 +567,6 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); - if (msg->len == 0) - return -EINVAL; - /* * The MX28 I2C IP block can only do PIO READ for transfer of to up * 4 bytes of length. The write transfer is not limited as it can use @@ -683,6 +680,10 @@ static const struct i2c_algorithm mxs_i2c_algo = { .functionality = mxs_i2c_func, }; +static const struct i2c_adapter_quirks mxs_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, uint32_t speed) { /* The I2C block clock runs at 24MHz */ @@ -854,6 +855,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name)); adap->owner = THIS_MODULE; adap->algo = &mxs_i2c_algo; + adap->quirks = &mxs_i2c_quirks; adap->dev.parent = dev; adap->nr = pdev->id; adap->dev.of_node = pdev->dev.of_node; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 88444ef74943..87f9caacba85 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -2,7 +2,7 @@ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller * (https://opencores.org/project/i2c/overview) * - * Peter Korsgaard <jacmet@sunsite.dk> + * Peter Korsgaard <peter@korsgaard.com> * * Support for the GRLIB port of the controller by * Andreas Larsson <andreas@gaisler.com> @@ -576,7 +576,7 @@ static struct platform_driver ocores_i2c_driver = { module_platform_driver(ocores_i2c_driver); -MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); +MODULE_AUTHOR("Peter Korsgaard <peter@korsgaard.com>"); MODULE_DESCRIPTION("OpenCores I2C bus driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ocores-i2c"); diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c new file mode 100644 index 000000000000..96b4572e6d9c --- /dev/null +++ b/drivers/i2c/busses/i2c-owl.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Actions Semiconductor Owl SoC's I2C driver + * + * Copyright (c) 2014 Actions Semi Inc. + * Author: David Liu <liuwei@actions-semi.com> + * + * Copyright (c) 2018 Linaro Ltd. + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_device.h> + +/* I2C registers */ +#define OWL_I2C_REG_CTL 0x0000 +#define OWL_I2C_REG_CLKDIV 0x0004 +#define OWL_I2C_REG_STAT 0x0008 +#define OWL_I2C_REG_ADDR 0x000C +#define OWL_I2C_REG_TXDAT 0x0010 +#define OWL_I2C_REG_RXDAT 0x0014 +#define OWL_I2C_REG_CMD 0x0018 +#define OWL_I2C_REG_FIFOCTL 0x001C +#define OWL_I2C_REG_FIFOSTAT 0x0020 +#define OWL_I2C_REG_DATCNT 0x0024 +#define OWL_I2C_REG_RCNT 0x0028 + +/* I2Cx_CTL Bit Mask */ +#define OWL_I2C_CTL_RB BIT(1) +#define OWL_I2C_CTL_GBCC(x) (((x) & 0x3) << 2) +#define OWL_I2C_CTL_GBCC_NONE OWL_I2C_CTL_GBCC(0) +#define OWL_I2C_CTL_GBCC_START OWL_I2C_CTL_GBCC(1) +#define OWL_I2C_CTL_GBCC_STOP OWL_I2C_CTL_GBCC(2) +#define OWL_I2C_CTL_GBCC_RSTART OWL_I2C_CTL_GBCC(3) +#define OWL_I2C_CTL_IRQE BIT(5) +#define OWL_I2C_CTL_EN BIT(7) +#define OWL_I2C_CTL_AE BIT(8) +#define OWL_I2C_CTL_SHSM BIT(10) + +#define OWL_I2C_DIV_FACTOR(x) ((x) & 0xff) + +/* I2Cx_STAT Bit Mask */ +#define OWL_I2C_STAT_RACK BIT(0) +#define OWL_I2C_STAT_BEB BIT(1) +#define OWL_I2C_STAT_IRQP BIT(2) +#define OWL_I2C_STAT_LAB BIT(3) +#define OWL_I2C_STAT_STPD BIT(4) +#define OWL_I2C_STAT_STAD BIT(5) +#define OWL_I2C_STAT_BBB BIT(6) +#define OWL_I2C_STAT_TCB BIT(7) +#define OWL_I2C_STAT_LBST BIT(8) +#define OWL_I2C_STAT_SAMB BIT(9) +#define OWL_I2C_STAT_SRGC BIT(10) + +/* I2Cx_CMD Bit Mask */ +#define OWL_I2C_CMD_SBE BIT(0) +#define OWL_I2C_CMD_RBE BIT(4) +#define OWL_I2C_CMD_DE BIT(8) +#define OWL_I2C_CMD_NS BIT(9) +#define OWL_I2C_CMD_SE BIT(10) +#define OWL_I2C_CMD_MSS BIT(11) +#define OWL_I2C_CMD_WRS BIT(12) +#define OWL_I2C_CMD_SECL BIT(15) + +#define OWL_I2C_CMD_AS(x) (((x) & 0x7) << 1) +#define OWL_I2C_CMD_SAS(x) (((x) & 0x7) << 5) + +/* I2Cx_FIFOCTL Bit Mask */ +#define OWL_I2C_FIFOCTL_NIB BIT(0) +#define OWL_I2C_FIFOCTL_RFR BIT(1) +#define OWL_I2C_FIFOCTL_TFR BIT(2) + +/* I2Cc_FIFOSTAT Bit Mask */ +#define OWL_I2C_FIFOSTAT_RNB BIT(1) +#define OWL_I2C_FIFOSTAT_RFE BIT(2) +#define OWL_I2C_FIFOSTAT_TFF BIT(5) +#define OWL_I2C_FIFOSTAT_TFD GENMASK(23, 16) +#define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8) + +/* I2C bus timeout */ +#define OWL_I2C_TIMEOUT msecs_to_jiffies(4 * 1000) + +#define OWL_I2C_MAX_RETRIES 50 + +#define OWL_I2C_DEF_SPEED_HZ 100000 +#define OWL_I2C_MAX_SPEED_HZ 400000 + +struct owl_i2c_dev { + struct i2c_adapter adap; + struct i2c_msg *msg; + struct completion msg_complete; + struct clk *clk; + spinlock_t lock; + void __iomem *base; + unsigned long clk_rate; + u32 bus_freq; + u32 msg_ptr; + int err; +}; + +static void owl_i2c_update_reg(void __iomem *reg, unsigned int val, bool state) +{ + unsigned int regval; + + regval = readl(reg); + + if (state) + regval |= val; + else + regval &= ~val; + + writel(regval, reg); +} + +static void owl_i2c_reset(struct owl_i2c_dev *i2c_dev) +{ + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, + OWL_I2C_CTL_EN, false); + mdelay(1); + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, + OWL_I2C_CTL_EN, true); + + /* Clear status registers */ + writel(0, i2c_dev->base + OWL_I2C_REG_STAT); +} + +static int owl_i2c_reset_fifo(struct owl_i2c_dev *i2c_dev) +{ + unsigned int val, timeout = 0; + + /* Reset FIFO */ + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, + OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR, + true); + + /* Wait 50ms for FIFO reset complete */ + do { + val = readl(i2c_dev->base + OWL_I2C_REG_FIFOCTL); + if (!(val & (OWL_I2C_FIFOCTL_RFR | OWL_I2C_FIFOCTL_TFR))) + break; + usleep_range(500, 1000); + } while (timeout++ < OWL_I2C_MAX_RETRIES); + + if (timeout > OWL_I2C_MAX_RETRIES) { + dev_err(&i2c_dev->adap.dev, "FIFO reset timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev) +{ + unsigned int val; + + val = DIV_ROUND_UP(i2c_dev->clk_rate, i2c_dev->bus_freq * 16); + + /* Set clock divider factor */ + writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV); +} + +static irqreturn_t owl_i2c_interrupt(int irq, void *_dev) +{ + struct owl_i2c_dev *i2c_dev = _dev; + struct i2c_msg *msg = i2c_dev->msg; + unsigned long flags; + unsigned int stat, fifostat; + + spin_lock_irqsave(&i2c_dev->lock, flags); + + i2c_dev->err = 0; + + /* Handle NACK from slave */ + fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT); + if (fifostat & OWL_I2C_FIFOSTAT_RNB) { + i2c_dev->err = -ENXIO; + goto stop; + } + + /* Handle bus error */ + stat = readl(i2c_dev->base + OWL_I2C_REG_STAT); + if (stat & OWL_I2C_STAT_BEB) { + i2c_dev->err = -EIO; + goto stop; + } + + /* Handle FIFO read */ + if (msg->flags & I2C_M_RD) { + while ((readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & + OWL_I2C_FIFOSTAT_RFE) && i2c_dev->msg_ptr < msg->len) { + msg->buf[i2c_dev->msg_ptr++] = readl(i2c_dev->base + + OWL_I2C_REG_RXDAT); + } + } else { + /* Handle the remaining bytes which were not sent */ + while (!(readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & + OWL_I2C_FIFOSTAT_TFF) && i2c_dev->msg_ptr < msg->len) { + writel(msg->buf[i2c_dev->msg_ptr++], + i2c_dev->base + OWL_I2C_REG_TXDAT); + } + } + +stop: + /* Clear pending interrupts */ + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT, + OWL_I2C_STAT_IRQP, true); + + complete_all(&i2c_dev->msg_complete); + spin_unlock_irqrestore(&i2c_dev->lock, flags); + + return IRQ_HANDLED; +} + +static u32 owl_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static int owl_i2c_check_bus_busy(struct i2c_adapter *adap) +{ + struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + unsigned long timeout; + + /* Check for Bus busy */ + timeout = jiffies + OWL_I2C_TIMEOUT; + while (readl(i2c_dev->base + OWL_I2C_REG_STAT) & OWL_I2C_STAT_BBB) { + if (time_after(jiffies, timeout)) { + dev_err(&adap->dev, "Bus busy timeout\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + struct i2c_msg *msg; + unsigned long time_left, flags; + unsigned int i2c_cmd, val; + unsigned int addr; + int ret, idx; + + spin_lock_irqsave(&i2c_dev->lock, flags); + + /* Reset I2C controller */ + owl_i2c_reset(i2c_dev); + + /* Set bus frequency */ + owl_i2c_set_freq(i2c_dev); + + /* + * Spinlock should be released before calling reset FIFO and + * bus busy check since those functions may sleep + */ + spin_unlock_irqrestore(&i2c_dev->lock, flags); + + /* Reset FIFO */ + ret = owl_i2c_reset_fifo(i2c_dev); + if (ret) + goto unlocked_err_exit; + + /* Check for bus busy */ + ret = owl_i2c_check_bus_busy(adap); + if (ret) + goto unlocked_err_exit; + + spin_lock_irqsave(&i2c_dev->lock, flags); + + /* Check for Arbitration lost */ + val = readl(i2c_dev->base + OWL_I2C_REG_STAT); + if (val & OWL_I2C_STAT_LAB) { + val &= ~OWL_I2C_STAT_LAB; + writel(val, i2c_dev->base + OWL_I2C_REG_STAT); + ret = -EAGAIN; + goto err_exit; + } + + reinit_completion(&i2c_dev->msg_complete); + + /* Enable I2C controller interrupt */ + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, + OWL_I2C_CTL_IRQE, true); + + /* + * Select: FIFO enable, Master mode, Stop enable, Data count enable, + * Send start bit + */ + i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE | + OWL_I2C_CMD_NS | OWL_I2C_CMD_DE | OWL_I2C_CMD_SBE; + + /* Handle repeated start condition */ + if (num > 1) { + /* Set internal address length and enable repeated start */ + i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) | + OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE; + + /* Write slave address */ + addr = i2c_8bit_addr_from_msg(&msgs[0]); + writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); + + /* Write internal register address */ + for (idx = 0; idx < msgs[0].len; idx++) + writel(msgs[0].buf[idx], + i2c_dev->base + OWL_I2C_REG_TXDAT); + + msg = &msgs[1]; + } else { + /* Set address length */ + i2c_cmd |= OWL_I2C_CMD_AS(1); + msg = &msgs[0]; + } + + i2c_dev->msg = msg; + i2c_dev->msg_ptr = 0; + + /* Set data count for the message */ + writel(msg->len, i2c_dev->base + OWL_I2C_REG_DATCNT); + + addr = i2c_8bit_addr_from_msg(msg); + writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); + + if (!(msg->flags & I2C_M_RD)) { + /* Write data to FIFO */ + for (idx = 0; idx < msg->len; idx++) { + /* Check for FIFO full */ + if (readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT) & + OWL_I2C_FIFOSTAT_TFF) + break; + + writel(msg->buf[idx], + i2c_dev->base + OWL_I2C_REG_TXDAT); + } + + i2c_dev->msg_ptr = idx; + } + + /* Ignore the NACK if needed */ + if (msg->flags & I2C_M_IGNORE_NAK) + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, + OWL_I2C_FIFOCTL_NIB, true); + else + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOCTL, + OWL_I2C_FIFOCTL_NIB, false); + + /* Start the transfer */ + writel(i2c_cmd, i2c_dev->base + OWL_I2C_REG_CMD); + + spin_unlock_irqrestore(&i2c_dev->lock, flags); + + time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, + adap->timeout); + + spin_lock_irqsave(&i2c_dev->lock, flags); + if (time_left == 0) { + dev_err(&adap->dev, "Transaction timed out\n"); + /* Send stop condition and release the bus */ + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, + OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB, + true); + ret = -ETIMEDOUT; + goto err_exit; + } + + ret = i2c_dev->err < 0 ? i2c_dev->err : num; + +err_exit: + spin_unlock_irqrestore(&i2c_dev->lock, flags); + +unlocked_err_exit: + /* Disable I2C controller */ + owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL, + OWL_I2C_CTL_EN, false); + + return ret; +} + +static const struct i2c_algorithm owl_i2c_algorithm = { + .master_xfer = owl_i2c_master_xfer, + .functionality = owl_i2c_func, +}; + +static const struct i2c_adapter_quirks owl_i2c_quirks = { + .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST, + .max_read_len = 240, + .max_write_len = 240, + .max_comb_1st_msg_len = 6, + .max_comb_2nd_msg_len = 240, +}; + +static int owl_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct owl_i2c_dev *i2c_dev; + struct resource *res; + int ret, irq; + + i2c_dev = devm_kzalloc(dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c_dev->base = devm_ioremap_resource(dev, res); + if (IS_ERR(i2c_dev->base)) + return PTR_ERR(i2c_dev->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to get IRQ number\n"); + return irq; + } + + if (of_property_read_u32(dev->of_node, "clock-frequency", + &i2c_dev->bus_freq)) + i2c_dev->bus_freq = OWL_I2C_DEF_SPEED_HZ; + + /* We support only frequencies of 100k and 400k for now */ + if (i2c_dev->bus_freq != OWL_I2C_DEF_SPEED_HZ && + i2c_dev->bus_freq != OWL_I2C_MAX_SPEED_HZ) { + dev_err(dev, "invalid clock-frequency %d\n", i2c_dev->bus_freq); + return -EINVAL; + } + + i2c_dev->clk = devm_clk_get(dev, NULL); + if (IS_ERR(i2c_dev->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(i2c_dev->clk); + } + + ret = clk_prepare_enable(i2c_dev->clk); + if (ret) + return ret; + + i2c_dev->clk_rate = clk_get_rate(i2c_dev->clk); + if (!i2c_dev->clk_rate) { + dev_err(dev, "input clock rate should not be zero\n"); + ret = -EINVAL; + goto disable_clk; + } + + init_completion(&i2c_dev->msg_complete); + spin_lock_init(&i2c_dev->lock); + i2c_dev->adap.owner = THIS_MODULE; + i2c_dev->adap.algo = &owl_i2c_algorithm; + i2c_dev->adap.timeout = OWL_I2C_TIMEOUT; + i2c_dev->adap.quirks = &owl_i2c_quirks; + i2c_dev->adap.dev.parent = dev; + i2c_dev->adap.dev.of_node = dev->of_node; + snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name), + "%s", "OWL I2C adapter"); + i2c_set_adapdata(&i2c_dev->adap, i2c_dev); + + platform_set_drvdata(pdev, i2c_dev); + + ret = devm_request_irq(dev, irq, owl_i2c_interrupt, 0, pdev->name, + i2c_dev); + if (ret) { + dev_err(dev, "failed to request irq %d\n", irq); + goto disable_clk; + } + + return i2c_add_adapter(&i2c_dev->adap); + +disable_clk: + clk_disable_unprepare(i2c_dev->clk); + + return ret; +} + +static const struct of_device_id owl_i2c_of_match[] = { + { .compatible = "actions,s900-i2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, owl_i2c_of_match); + +static struct platform_driver owl_i2c_driver = { + .probe = owl_i2c_probe, + .driver = { + .name = "owl-i2c", + .of_match_table = of_match_ptr(owl_i2c_of_match), + }, +}; +module_platform_driver(owl_i2c_driver); + +MODULE_AUTHOR("David Liu <liuwei@actions-semi.com>"); +MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); +MODULE_DESCRIPTION("Actions Semiconductor Owl SoC's I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 55fd5c6f3cca..50803e5d995b 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -365,7 +365,6 @@ static int pasemi_smb_probe(struct pci_dev *dev, smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; - smbus->adapter.nr = PCI_FUNC(dev->devfn); /* set up the sysfs linkage to our parent device */ smbus->adapter.dev.parent = &dev->dev; @@ -373,7 +372,7 @@ static int pasemi_smb_probe(struct pci_dev *dev, reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | (CLK_100K_DIV & CTL_CLK_M))); - error = i2c_add_numbered_adapter(&smbus->adapter); + error = i2c_add_adapter(&smbus->adapter); if (error) goto out_release_region; diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index dae8ac618a52..0829cb696d9d 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -444,16 +444,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd( { enum pmcmsptwi_xfer_result retval; - if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) || - (cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) || - (cmd->type == MSP_TWI_CMD_WRITE_READ && - (cmd->read_len == 0 || cmd->write_len == 0))) { - dev_err(&pmcmsptwi_adapter.dev, - "%s: Cannot transfer less than 1 byte\n", - __func__); - return -EINVAL; - } - mutex_lock(&data->lock); dev_dbg(&pmcmsptwi_adapter.dev, "Setting address to 0x%04x\n", cmd->addr); @@ -532,11 +522,6 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap, cmd.write_data = msg->buf; } - if (msg->len == 0) { - dev_err(&adap->dev, "Zero-byte messages unsupported\n"); - return -EINVAL; - } - cmd.addr = msg->addr; if (msg->flags & I2C_M_TEN) { @@ -578,7 +563,7 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter) } static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = { - .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN, .max_write_len = MSP_MAX_BYTES_PER_RW, .max_read_len = MSP_MAX_BYTES_PER_RW, .max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW, diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c new file mode 100644 index 000000000000..36732eb688a4 --- /dev/null +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -0,0 +1,673 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/qcom-geni-se.h> +#include <linux/spinlock.h> + +#define SE_I2C_TX_TRANS_LEN 0x26c +#define SE_I2C_RX_TRANS_LEN 0x270 +#define SE_I2C_SCL_COUNTERS 0x278 + +#define SE_I2C_ERR (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\ + M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN) +#define SE_I2C_ABORT BIT(1) + +/* M_CMD OP codes for I2C */ +#define I2C_WRITE 0x1 +#define I2C_READ 0x2 +#define I2C_WRITE_READ 0x3 +#define I2C_ADDR_ONLY 0x4 +#define I2C_BUS_CLEAR 0x6 +#define I2C_STOP_ON_BUS 0x7 +/* M_CMD params for I2C */ +#define PRE_CMD_DELAY BIT(0) +#define TIMESTAMP_BEFORE BIT(1) +#define STOP_STRETCH BIT(2) +#define TIMESTAMP_AFTER BIT(3) +#define POST_COMMAND_DELAY BIT(4) +#define IGNORE_ADD_NACK BIT(6) +#define READ_FINISHED_WITH_ACK BIT(7) +#define BYPASS_ADDR_PHASE BIT(8) +#define SLV_ADDR_MSK GENMASK(15, 9) +#define SLV_ADDR_SHFT 9 +/* I2C SCL COUNTER fields */ +#define HIGH_COUNTER_MSK GENMASK(29, 20) +#define HIGH_COUNTER_SHFT 20 +#define LOW_COUNTER_MSK GENMASK(19, 10) +#define LOW_COUNTER_SHFT 10 +#define CYCLE_COUNTER_MSK GENMASK(9, 0) + +enum geni_i2c_err_code { + GP_IRQ0, + NACK, + GP_IRQ2, + BUS_PROTO, + ARB_LOST, + GP_IRQ5, + GENI_OVERRUN, + GENI_ILLEGAL_CMD, + GENI_ABORT_DONE, + GENI_TIMEOUT, +}; + +#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \ + << 5) + +#define I2C_AUTO_SUSPEND_DELAY 250 +#define KHZ(freq) (1000 * freq) +#define PACKING_BYTES_PW 4 + +#define ABORT_TIMEOUT HZ +#define XFER_TIMEOUT HZ +#define RST_TIMEOUT HZ + +struct geni_i2c_dev { + struct geni_se se; + u32 tx_wm; + int irq; + int err; + struct i2c_adapter adap; + struct completion done; + struct i2c_msg *cur; + int cur_wr; + int cur_rd; + spinlock_t lock; + u32 clk_freq_out; + const struct geni_i2c_clk_fld *clk_fld; + int suspended; +}; + +struct geni_i2c_err_log { + int err; + const char *msg; +}; + +static const struct geni_i2c_err_log gi2c_log[] = { + [GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"}, + [NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"}, + [GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"}, + [BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unepxected start/stop"}, + [ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"}, + [GP_IRQ5] = {-EIO, "Unknown I2C err GP IRQ5"}, + [GENI_OVERRUN] = {-EIO, "Cmd overrun, check GENI cmd-state machine"}, + [GENI_ILLEGAL_CMD] = {-EIO, "Illegal cmd, check GENI cmd-state machine"}, + [GENI_ABORT_DONE] = {-ETIMEDOUT, "Abort after timeout successful"}, + [GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"}, +}; + +struct geni_i2c_clk_fld { + u32 clk_freq_out; + u8 clk_div; + u8 t_high_cnt; + u8 t_low_cnt; + u8 t_cycle_cnt; +}; + +/* + * Hardware uses the underlying formula to calculate time periods of + * SCL clock cycle. Firmware uses some additional cycles excluded from the + * below formula and it is confirmed that the time periods are within + * specification limits. + * + * time of high period of SCL: t_high = (t_high_cnt * clk_div) / source_clock + * time of low period of SCL: t_low = (t_low_cnt * clk_div) / source_clock + * time of full period of SCL: t_cycle = (t_cycle_cnt * clk_div) / source_clock + * clk_freq_out = t / t_cycle + * source_clock = 19.2 MHz + */ +static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { + {KHZ(100), 7, 10, 11, 26}, + {KHZ(400), 2, 5, 12, 24}, + {KHZ(1000), 1, 3, 9, 18}, +}; + +static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) +{ + int i; + const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; + + for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { + if (itr->clk_freq_out == gi2c->clk_freq_out) { + gi2c->clk_fld = itr; + return 0; + } + } + return -EINVAL; +} + +static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c) +{ + const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; + u32 val; + + writel_relaxed(0, gi2c->se.base + SE_GENI_CLK_SEL); + + val = (itr->clk_div << CLK_DIV_SHFT) | SER_CLK_EN; + writel_relaxed(val, gi2c->se.base + GENI_SER_M_CLK_CFG); + + val = itr->t_high_cnt << HIGH_COUNTER_SHFT; + val |= itr->t_low_cnt << LOW_COUNTER_SHFT; + val |= itr->t_cycle_cnt; + writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS); +} + +static void geni_i2c_err_misc(struct geni_i2c_dev *gi2c) +{ + u32 m_cmd = readl_relaxed(gi2c->se.base + SE_GENI_M_CMD0); + u32 m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); + u32 geni_s = readl_relaxed(gi2c->se.base + SE_GENI_STATUS); + u32 geni_ios = readl_relaxed(gi2c->se.base + SE_GENI_IOS); + u32 dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN); + u32 rx_st, tx_st; + + if (dma) { + rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); + tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); + } else { + rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS); + tx_st = readl_relaxed(gi2c->se.base + SE_GENI_TX_FIFO_STATUS); + } + dev_dbg(gi2c->se.dev, "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n", + dma, tx_st, rx_st, m_stat); + dev_dbg(gi2c->se.dev, "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n", + m_cmd, geni_s, geni_ios); +} + +static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) +{ + if (!gi2c->err) + gi2c->err = gi2c_log[err].err; + if (gi2c->cur) + dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n", + gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags); + + if (err != NACK && err != GENI_ABORT_DONE) { + dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg); + geni_i2c_err_misc(gi2c); + } +} + +static irqreturn_t geni_i2c_irq(int irq, void *dev) +{ + struct geni_i2c_dev *gi2c = dev; + int j; + u32 m_stat; + u32 rx_st; + u32 dm_tx_st; + u32 dm_rx_st; + u32 dma; + struct i2c_msg *cur; + unsigned long flags; + + spin_lock_irqsave(&gi2c->lock, flags); + m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); + rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS); + dm_tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); + dm_rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); + dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN); + cur = gi2c->cur; + + if (!cur || + m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) || + dm_rx_st & (DM_I2C_CB_ERR)) { + if (m_stat & M_GP_IRQ_1_EN) + geni_i2c_err(gi2c, NACK); + if (m_stat & M_GP_IRQ_3_EN) + geni_i2c_err(gi2c, BUS_PROTO); + if (m_stat & M_GP_IRQ_4_EN) + geni_i2c_err(gi2c, ARB_LOST); + if (m_stat & M_CMD_OVERRUN_EN) + geni_i2c_err(gi2c, GENI_OVERRUN); + if (m_stat & M_ILLEGAL_CMD_EN) + geni_i2c_err(gi2c, GENI_ILLEGAL_CMD); + if (m_stat & M_CMD_ABORT_EN) + geni_i2c_err(gi2c, GENI_ABORT_DONE); + if (m_stat & M_GP_IRQ_0_EN) + geni_i2c_err(gi2c, GP_IRQ0); + + /* Disable the TX Watermark interrupt to stop TX */ + if (!dma) + writel_relaxed(0, gi2c->se.base + + SE_GENI_TX_WATERMARK_REG); + goto irqret; + } + + if (dma) { + dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n", + dm_tx_st, dm_rx_st); + goto irqret; + } + + if (cur->flags & I2C_M_RD && + m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) { + u32 rxcnt = rx_st & RX_FIFO_WC_MSK; + + for (j = 0; j < rxcnt; j++) { + u32 val; + int p = 0; + + val = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFOn); + while (gi2c->cur_rd < cur->len && p < sizeof(val)) { + cur->buf[gi2c->cur_rd++] = val & 0xff; + val >>= 8; + p++; + } + if (gi2c->cur_rd == cur->len) + break; + } + } else if (!(cur->flags & I2C_M_RD) && + m_stat & M_TX_FIFO_WATERMARK_EN) { + for (j = 0; j < gi2c->tx_wm; j++) { + u32 temp; + u32 val = 0; + int p = 0; + + while (gi2c->cur_wr < cur->len && p < sizeof(val)) { + temp = cur->buf[gi2c->cur_wr++]; + val |= temp << (p * 8); + p++; + } + writel_relaxed(val, gi2c->se.base + SE_GENI_TX_FIFOn); + /* TX Complete, Disable the TX Watermark interrupt */ + if (gi2c->cur_wr == cur->len) { + writel_relaxed(0, gi2c->se.base + + SE_GENI_TX_WATERMARK_REG); + break; + } + } + } +irqret: + if (m_stat) + writel_relaxed(m_stat, gi2c->se.base + SE_GENI_M_IRQ_CLEAR); + + if (dma) { + if (dm_tx_st) + writel_relaxed(dm_tx_st, gi2c->se.base + + SE_DMA_TX_IRQ_CLR); + if (dm_rx_st) + writel_relaxed(dm_rx_st, gi2c->se.base + + SE_DMA_RX_IRQ_CLR); + } + /* if this is err with done-bit not set, handle that through timeout. */ + if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN) + complete(&gi2c->done); + else if (dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE) + complete(&gi2c->done); + else if (dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE) + complete(&gi2c->done); + + spin_unlock_irqrestore(&gi2c->lock, flags); + return IRQ_HANDLED; +} + +static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c) +{ + u32 val; + unsigned long time_left = ABORT_TIMEOUT; + unsigned long flags; + + spin_lock_irqsave(&gi2c->lock, flags); + geni_i2c_err(gi2c, GENI_TIMEOUT); + gi2c->cur = NULL; + geni_se_abort_m_cmd(&gi2c->se); + spin_unlock_irqrestore(&gi2c->lock, flags); + do { + time_left = wait_for_completion_timeout(&gi2c->done, time_left); + val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); + } while (!(val & M_CMD_ABORT_EN) && time_left); + + if (!(val & M_CMD_ABORT_EN)) + dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n"); +} + +static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c) +{ + u32 val; + unsigned long time_left = RST_TIMEOUT; + + writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST); + do { + time_left = wait_for_completion_timeout(&gi2c->done, time_left); + val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); + } while (!(val & RX_RESET_DONE) && time_left); + + if (!(val & RX_RESET_DONE)) + dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n"); +} + +static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c) +{ + u32 val; + unsigned long time_left = RST_TIMEOUT; + + writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST); + do { + time_left = wait_for_completion_timeout(&gi2c->done, time_left); + val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); + } while (!(val & TX_RESET_DONE) && time_left); + + if (!(val & TX_RESET_DONE)) + dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n"); +} + +static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, + u32 m_param) +{ + dma_addr_t rx_dma; + enum geni_se_xfer_mode mode; + unsigned long time_left = XFER_TIMEOUT; + + gi2c->cur = msg; + mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO; + geni_se_select_mode(&gi2c->se, mode); + writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN); + geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param); + if (mode == GENI_SE_DMA) { + int ret; + + ret = geni_se_rx_dma_prep(&gi2c->se, msg->buf, msg->len, + &rx_dma); + if (ret) { + mode = GENI_SE_FIFO; + geni_se_select_mode(&gi2c->se, mode); + } + } + + time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); + if (!time_left) + geni_i2c_abort_xfer(gi2c); + + gi2c->cur_rd = 0; + if (mode == GENI_SE_DMA) { + if (gi2c->err) + geni_i2c_rx_fsm_rst(gi2c); + geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len); + } + return gi2c->err; +} + +static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, + u32 m_param) +{ + dma_addr_t tx_dma; + enum geni_se_xfer_mode mode; + unsigned long time_left; + + gi2c->cur = msg; + mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO; + geni_se_select_mode(&gi2c->se, mode); + writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN); + geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param); + if (mode == GENI_SE_DMA) { + int ret; + + ret = geni_se_tx_dma_prep(&gi2c->se, msg->buf, msg->len, + &tx_dma); + if (ret) { + mode = GENI_SE_FIFO; + geni_se_select_mode(&gi2c->se, mode); + } + } + + if (mode == GENI_SE_FIFO) /* Get FIFO IRQ */ + writel_relaxed(1, gi2c->se.base + SE_GENI_TX_WATERMARK_REG); + + time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); + if (!time_left) + geni_i2c_abort_xfer(gi2c); + + gi2c->cur_wr = 0; + if (mode == GENI_SE_DMA) { + if (gi2c->err) + geni_i2c_tx_fsm_rst(gi2c); + geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len); + } + return gi2c->err; +} + +static int geni_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], + int num) +{ + struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap); + int i, ret; + + gi2c->err = 0; + reinit_completion(&gi2c->done); + ret = pm_runtime_get_sync(gi2c->se.dev); + if (ret < 0) { + dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret); + pm_runtime_put_noidle(gi2c->se.dev); + /* Set device in suspended since resume failed */ + pm_runtime_set_suspended(gi2c->se.dev); + return ret; + } + + qcom_geni_i2c_conf(gi2c); + for (i = 0; i < num; i++) { + u32 m_param = i < (num - 1) ? STOP_STRETCH : 0; + + m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK); + + if (msgs[i].flags & I2C_M_RD) + ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param); + else + ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param); + + if (ret) + break; + } + if (ret == 0) + ret = num; + + pm_runtime_mark_last_busy(gi2c->se.dev); + pm_runtime_put_autosuspend(gi2c->se.dev); + gi2c->cur = NULL; + gi2c->err = 0; + return ret; +} + +static u32 geni_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +static const struct i2c_algorithm geni_i2c_algo = { + .master_xfer = geni_i2c_xfer, + .functionality = geni_i2c_func, +}; + +static int geni_i2c_probe(struct platform_device *pdev) +{ + struct geni_i2c_dev *gi2c; + struct resource *res; + u32 proto, tx_depth; + int ret; + + gi2c = devm_kzalloc(&pdev->dev, sizeof(*gi2c), GFP_KERNEL); + if (!gi2c) + return -ENOMEM; + + gi2c->se.dev = &pdev->dev; + gi2c->se.wrapper = dev_get_drvdata(pdev->dev.parent); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gi2c->se.base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gi2c->se.base)) + return PTR_ERR(gi2c->se.base); + + gi2c->se.clk = devm_clk_get(&pdev->dev, "se"); + if (IS_ERR(gi2c->se.clk)) { + ret = PTR_ERR(gi2c->se.clk); + dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); + return ret; + } + + ret = device_property_read_u32(&pdev->dev, "clock-frequency", + &gi2c->clk_freq_out); + if (ret) { + dev_info(&pdev->dev, + "Bus frequency not specified, default to 100kHz.\n"); + gi2c->clk_freq_out = KHZ(100); + } + + gi2c->irq = platform_get_irq(pdev, 0); + if (gi2c->irq < 0) { + dev_err(&pdev->dev, "IRQ error for i2c-geni\n"); + return gi2c->irq; + } + + ret = geni_i2c_clk_map_idx(gi2c); + if (ret) { + dev_err(&pdev->dev, "Invalid clk frequency %d Hz: %d\n", + gi2c->clk_freq_out, ret); + return ret; + } + + gi2c->adap.algo = &geni_i2c_algo; + init_completion(&gi2c->done); + spin_lock_init(&gi2c->lock); + platform_set_drvdata(pdev, gi2c); + ret = devm_request_irq(&pdev->dev, gi2c->irq, geni_i2c_irq, + IRQF_TRIGGER_HIGH, "i2c_geni", gi2c); + if (ret) { + dev_err(&pdev->dev, "Request_irq failed:%d: err:%d\n", + gi2c->irq, ret); + return ret; + } + /* Disable the interrupt so that the system can enter low-power mode */ + disable_irq(gi2c->irq); + i2c_set_adapdata(&gi2c->adap, gi2c); + gi2c->adap.dev.parent = &pdev->dev; + gi2c->adap.dev.of_node = pdev->dev.of_node; + strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name)); + + ret = geni_se_resources_on(&gi2c->se); + if (ret) { + dev_err(&pdev->dev, "Error turning on resources %d\n", ret); + return ret; + } + proto = geni_se_read_proto(&gi2c->se); + tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se); + if (proto != GENI_SE_I2C) { + dev_err(&pdev->dev, "Invalid proto %d\n", proto); + geni_se_resources_off(&gi2c->se); + return -ENXIO; + } + gi2c->tx_wm = tx_depth - 1; + geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth); + geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, PACKING_BYTES_PW, + true, true, true); + ret = geni_se_resources_off(&gi2c->se); + if (ret) { + dev_err(&pdev->dev, "Error turning off resources %d\n", ret); + return ret; + } + + dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); + + ret = i2c_add_adapter(&gi2c->adap); + if (ret) { + dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret); + return ret; + } + + gi2c->suspended = 1; + pm_runtime_set_suspended(gi2c->se.dev); + pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY); + pm_runtime_use_autosuspend(gi2c->se.dev); + pm_runtime_enable(gi2c->se.dev); + + return 0; +} + +static int geni_i2c_remove(struct platform_device *pdev) +{ + struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); + + pm_runtime_disable(gi2c->se.dev); + i2c_del_adapter(&gi2c->adap); + return 0; +} + +static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) +{ + int ret; + struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + + disable_irq(gi2c->irq); + ret = geni_se_resources_off(&gi2c->se); + if (ret) { + enable_irq(gi2c->irq); + return ret; + + } else { + gi2c->suspended = 1; + } + + return 0; +} + +static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) +{ + int ret; + struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + + ret = geni_se_resources_on(&gi2c->se); + if (ret) + return ret; + + enable_irq(gi2c->irq); + gi2c->suspended = 0; + return 0; +} + +static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev) +{ + struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); + + if (!gi2c->suspended) { + geni_i2c_runtime_suspend(dev); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + } + return 0; +} + +static const struct dev_pm_ops geni_i2c_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, NULL) + SET_RUNTIME_PM_OPS(geni_i2c_runtime_suspend, geni_i2c_runtime_resume, + NULL) +}; + +static const struct of_device_id geni_i2c_dt_match[] = { + { .compatible = "qcom,geni-i2c" }, + {} +}; +MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); + +static struct platform_driver geni_i2c_driver = { + .probe = geni_i2c_probe, + .remove = geni_i2c_remove, + .driver = { + .name = "geni_i2c", + .pm = &geni_i2c_pm_ops, + .of_match_table = geni_i2c_dt_match, + }, +}; + +module_platform_driver(geni_i2c_driver); + +MODULE_DESCRIPTION("I2C Controller Driver for GENI based QUP cores"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 3c1c817f6968..52cf42b32f0a 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the Renesas R-Car I2C unit * @@ -9,16 +10,8 @@ * * This file is based on the drivers/i2c/busses/i2c-sh7760.c * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/dmaengine.h> @@ -112,9 +105,10 @@ #define ID_ARBLOST (1 << 3) #define ID_NACK (1 << 4) /* persistent flags */ -#define ID_P_NO_RXDMA (1 << 30) /* HW forbids RXDMA sometimes */ -#define ID_P_PM_BLOCKED (1 << 31) -#define ID_P_MASK (ID_P_PM_BLOCKED | ID_P_NO_RXDMA) +#define ID_P_REP_AFTER_RD BIT(29) +#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */ +#define ID_P_PM_BLOCKED BIT(31) +#define ID_P_MASK GENMASK(31, 29) enum rcar_i2c_type { I2C_RCAR_GEN1, @@ -183,8 +177,6 @@ static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val) rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); }; -/* No get_sda, because the HW only reports its bus free logic, not SDA itself */ - static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) { struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); @@ -197,10 +189,19 @@ static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); }; +static int rcar_i2c_get_bus_free(struct i2c_adapter *adap) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + return !(rcar_i2c_read(priv, ICMCR) & FSDA); + +}; + static struct i2c_bus_recovery_info rcar_i2c_bri = { .get_scl = rcar_i2c_get_scl, .set_scl = rcar_i2c_set_scl, .set_sda = rcar_i2c_set_sda, + .get_bus_free = rcar_i2c_get_bus_free, .recover_bus = i2c_generic_scl_recovery, }; static void rcar_i2c_init(struct rcar_i2c_priv *priv) @@ -215,7 +216,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) { - int i, ret; + int i; for (i = 0; i < LOOP_TIMEOUT; i++) { /* make sure that bus is not busy */ @@ -226,13 +227,7 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) /* Waiting did not help, try to recover */ priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; - ret = i2c_recover_bus(&priv->adap); - - /* No failure when recovering, so check bus busy bit again */ - if (ret == 0) - ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0; - - return ret; + return i2c_recover_bus(&priv->adap); } static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) @@ -343,7 +338,10 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMSR, 0); rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); } else { - rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); + if (priv->flags & ID_P_REP_AFTER_RD) + priv->flags &= ~ID_P_REP_AFTER_RD; + else + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); rcar_i2c_write(priv, ICMSR, 0); } rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); @@ -548,15 +546,15 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) priv->pos++; } - /* - * If next received data is the _LAST_, go to STOP phase. Might be - * overwritten by REP START when setting up a new msg. Not elegant - * but the only stable sequence for REP START I have found so far. - * If you want to change this code, make sure sending one transfer with - * four messages (WR-RD-WR-RD) works! - */ - if (priv->pos + 1 >= msg->len) - rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); + /* If next received data is the _LAST_, go to new phase. */ + if (priv->pos + 1 == msg->len) { + if (priv->flags & ID_LAST_MSG) { + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); + } else { + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); + priv->flags |= ID_P_REP_AFTER_RD; + } + } if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG)) rcar_i2c_next_msg(priv); @@ -624,9 +622,11 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) struct rcar_i2c_priv *priv = ptr; u32 msr, val; - /* Clear START or STOP as soon as we can */ - val = rcar_i2c_read(priv, ICMCR); - rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); + /* Clear START or STOP immediately, except for REPSTART after read */ + if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) { + val = rcar_i2c_read(priv, ICMCR); + rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); + } msr = rcar_i2c_read(priv, ICMSR); @@ -795,14 +795,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, if (ret < 0) goto out; - for (i = 0; i < num; i++) { - /* This HW can't send STOP after address phase */ - if (msgs[i].len == 0) { - ret = -EOPNOTSUPP; - goto out; - } + for (i = 0; i < num; i++) rcar_i2c_request_dma(priv, msgs + i); - } /* init first message */ priv->msg = msgs; @@ -889,6 +883,10 @@ static const struct i2c_algorithm rcar_i2c_algo = { .unreg_slave = rcar_unreg_slave, }; +static const struct i2c_adapter_quirks rcar_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, @@ -942,6 +940,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) adap->dev.parent = dev; adap->dev.of_node = dev->of_node; adap->bus_recovery_info = &rcar_i2c_bri; + adap->quirks = &rcar_i2c_quirks; i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 5f1fca7880b1..b75ff144b570 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas RIIC driver * * Copyright (C) 2013 Wolfram Sang <wsa@sang-engineering.com> * Copyright (C) 2013 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ /* diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 9fe2b6951895..2f2e28d60ef5 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -919,9 +919,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || (val == CPUFREQ_PRECHANGE && delta_f > 0)) { - i2c_lock_adapter(&i2c->adap); + i2c_lock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER); ret = s3c24xx_i2c_clockrate(i2c, &got); - i2c_unlock_adapter(&i2c->adap); + i2c_unlock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER); if (ret < 0) dev_err(i2c->dev, "cannot find frequency (%d)\n", ret); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 5fda4188a9e5..439e8778f849 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH Mobile I2C Controller * @@ -7,15 +8,6 @@ * * Portions of the code based on out-of-tree driver i2c-sh7343.c * Copyright (c) 2006 Carlos Munoz <carlos@kenati.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/clk.h> @@ -613,11 +605,6 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, bool do_init) { - if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) { - dev_err(pd->dev, "Unsupported zero length i2c read\n"); - return -EOPNOTSUPP; - } - if (do_init) { /* Initialize channel registers */ iic_wr(pd, ICCR, ICCR_SCP); @@ -758,6 +745,10 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = { .master_xfer = sh_mobile_i2c_xfer, }; +static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN_READ, +}; + /* * r8a7740 chip has lasting errata on I2C I/O pad reset. * this is work-around for it. @@ -925,6 +916,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) adap->owner = THIS_MODULE; adap->algo = &sh_mobile_i2c_algorithm; + adap->quirks = &sh_mobile_i2c_quirks; adap->dev.parent = &dev->dev; adap->retries = 5; adap->nr = dev->id; diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 4053259bccb8..a94e724f51dc 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -590,9 +590,9 @@ static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev) { struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); - i2c_lock_adapter(&i2c_dev->adap); + i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); i2c_dev->is_suspended = true; - i2c_unlock_adapter(&i2c_dev->adap); + i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); return pm_runtime_force_suspend(pdev); } @@ -601,9 +601,9 @@ static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev) { struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev); - i2c_lock_adapter(&i2c_dev->adap); + i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); i2c_dev->is_suspended = false; - i2c_unlock_adapter(&i2c_dev->adap); + i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); return pm_runtime_force_resume(pdev); } diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index fce52bdab2b7..5503fa171df0 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -673,12 +673,6 @@ static int stu300_xfer_msg(struct i2c_adapter *adap, msg->addr, msg->len, msg->flags, stop); } - /* Zero-length messages are not supported by this hardware */ - if (msg->len == 0) { - ret = -EINVAL; - goto exit_disable; - } - /* * For some reason, sending the address sometimes fails when running * on the 13 MHz clock. No interrupt arrives. This is a work around, @@ -863,6 +857,10 @@ static const struct i2c_algorithm stu300_algo = { .functionality = stu300_func, }; +static const struct i2c_adapter_quirks stu300_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + static int stu300_probe(struct platform_device *pdev) { struct stu300_dev *dev; @@ -920,6 +918,8 @@ static int stu300_probe(struct platform_device *pdev) adap->algo = &stu300_algo; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; + adap->quirks = &stu300_quirks; + i2c_set_adapdata(adap, dev); /* i2c device drivers may be active on return from add_adapter() */ diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 797def5319f1..60c8561fbe65 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -115,6 +115,18 @@ #define I2C_CONFIG_LOAD_TIMEOUT 1000000 +#define I2C_MST_FIFO_CONTROL 0x0b4 +#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0) +#define I2C_MST_FIFO_CONTROL_TX_FLUSH BIT(1) +#define I2C_MST_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 4) +#define I2C_MST_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 16) + +#define I2C_MST_FIFO_STATUS 0x0b8 +#define I2C_MST_FIFO_STATUS_RX_MASK 0xff +#define I2C_MST_FIFO_STATUS_RX_SHIFT 0 +#define I2C_MST_FIFO_STATUS_TX_MASK 0xff0000 +#define I2C_MST_FIFO_STATUS_TX_SHIFT 16 + /* * msg_end_type: The bus control which need to be send at end of transfer. * @MSG_END_STOP: Send stop pulse at end of transfer. @@ -154,6 +166,7 @@ struct tegra_i2c_hw_feature { u16 clk_divisor_fast_plus_mode; bool has_multi_master_mode; bool has_slcg_override_reg; + bool has_mst_fifo; }; /** @@ -266,13 +279,24 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) { unsigned long timeout = jiffies + HZ; - u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); + unsigned int offset; + u32 mask, val; + + if (i2c_dev->hw->has_mst_fifo) { + mask = I2C_MST_FIFO_CONTROL_TX_FLUSH | + I2C_MST_FIFO_CONTROL_RX_FLUSH; + offset = I2C_MST_FIFO_CONTROL; + } else { + mask = I2C_FIFO_CONTROL_TX_FLUSH | + I2C_FIFO_CONTROL_RX_FLUSH; + offset = I2C_FIFO_CONTROL; + } - val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; - i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); + val = i2c_readl(i2c_dev, offset); + val |= mask; + i2c_writel(i2c_dev, val, offset); - while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) & - (I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) { + while (i2c_readl(i2c_dev, offset) & mask) { if (time_after(jiffies, timeout)) { dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n"); return -ETIMEDOUT; @@ -290,9 +314,15 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; - val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); - rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> - I2C_FIFO_STATUS_RX_SHIFT; + if (i2c_dev->hw->has_mst_fifo) { + val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); + rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >> + I2C_MST_FIFO_STATUS_RX_SHIFT; + } else { + val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); + rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> + I2C_FIFO_STATUS_RX_SHIFT; + } /* Rounds down to not include partial word at the end of buf */ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; @@ -321,6 +351,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0); i2c_dev->msg_buf_remaining = buf_remaining; i2c_dev->msg_buf = buf; + return 0; } @@ -332,9 +363,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; - val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); - tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> - I2C_FIFO_STATUS_TX_SHIFT; + if (i2c_dev->hw->has_mst_fifo) { + val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); + tx_fifo_avail = (val & I2C_MST_FIFO_STATUS_TX_MASK) >> + I2C_MST_FIFO_STATUS_TX_SHIFT; + } else { + val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); + tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> + I2C_FIFO_STATUS_TX_SHIFT; + } /* Rounds down to not include partial word at the end of buf */ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; @@ -516,9 +553,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); } - val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | - 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; - i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); + if (i2c_dev->hw->has_mst_fifo) { + val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) | + I2C_MST_FIFO_CONTROL_RX_TRIG(1); + i2c_writel(i2c_dev, val, I2C_MST_FIFO_CONTROL); + } else { + val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | + 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; + i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); + } err = tegra_i2c_flush_fifos(i2c_dev); if (err) @@ -802,6 +845,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_config_load_reg = false, .has_multi_master_mode = false, .has_slcg_override_reg = false, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { @@ -814,6 +858,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_config_load_reg = false, .has_multi_master_mode = false, .has_slcg_override_reg = false, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { @@ -826,6 +871,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_config_load_reg = false, .has_multi_master_mode = false, .has_slcg_override_reg = false, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { @@ -838,6 +884,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { .has_config_load_reg = true, .has_multi_master_mode = false, .has_slcg_override_reg = true, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { @@ -850,10 +897,25 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { .has_config_load_reg = true, .has_multi_master_mode = true, .has_slcg_override_reg = true, + .has_mst_fifo = false, +}; + +static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { + .has_continue_xfer_support = true, + .has_per_pkt_xfer_complete_irq = true, + .has_single_clk_source = true, + .clk_divisor_hs_mode = 1, + .clk_divisor_std_fast_mode = 0x19, + .clk_divisor_fast_plus_mode = 0x10, + .has_config_load_reg = true, + .has_multi_master_mode = true, + .has_slcg_override_reg = true, + .has_mst_fifo = true, }; /* Match table for of_platform binding */ static const struct of_device_id tegra_i2c_of_match[] = { + { .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, }, { .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, }, { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, }, { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c index 484bfa15d58e..34cd4b308540 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -173,9 +173,6 @@ static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len, u8 offset; u32 xfer; - if (!len) - return -EOPNOTSUPP; - offset = buf[0]; xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset); xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); @@ -241,9 +238,6 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr) unsigned long timeout, stoptime, checktime; int nbytes, timedout; - if (!len) - return -EOPNOTSUPP; - xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra); xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); @@ -340,6 +334,10 @@ static const struct i2c_algorithm xlr_i2c_algo = { .functionality = xlr_func, }; +static const struct i2c_adapter_quirks xlr_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + static const struct xlr_i2c_config xlr_i2c_config_default = { .status_busy = XLR_I2C_BUS_BUSY, .cfg_extra = 0, @@ -427,6 +425,7 @@ static int xlr_i2c_probe(struct platform_device *pdev) priv->adap.owner = THIS_MODULE; priv->adap.algo_data = priv; priv->adap.algo = &xlr_i2c_algo; + priv->adap.quirks = &xlr_i2c_quirks; priv->adap.nr = pdev->id; priv->adap.class = I2C_CLASS_HWMON; snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c"); diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 7c3b4740b94b..32affd3fa8bd 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -453,8 +453,12 @@ static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, else dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", data_len, client->addr, cmd, ret); - } else { + /* 2 transfers must have completed successfully */ + } else if (ret == 2) { memcpy(data, buffer, data_len); + ret = 0; + } else { + ret = -EIO; } kfree(buffer); @@ -482,11 +486,16 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, msgs[0].buf = buffer; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - dev_err(&client->adapter->dev, "i2c write failed\n"); kfree(buffer); - return ret; + + if (ret < 0) { + dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); + return ret; + } + + /* 1 transfer must have completed successfully */ + return (ret == 1) ? 0 : -EIO; } static acpi_status @@ -590,8 +599,6 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, if (action == ACPI_READ) { status = acpi_gsb_i2c_read_bytes(client, command, gsb->data, info->access_length); - if (status > 0) - status = 0; } else { status = acpi_gsb_i2c_write_bytes(client, command, gsb->data, info->access_length); diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 15c95aaa484c..f15737763608 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -62,7 +62,7 @@ /* * core_lock protects i2c_adapter_idr, and guarantees that device detection, - * deletion of detected devices, and attach_adapter calls are serialized + * deletion of detected devices are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); @@ -158,6 +158,22 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val) gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val); } +static int i2c_generic_bus_free(struct i2c_adapter *adap) +{ + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + int ret = -EOPNOTSUPP; + + if (bri->get_bus_free) + ret = bri->get_bus_free(adap); + else if (bri->get_sda) + ret = bri->get_sda(adap); + + if (ret < 0) + return ret; + + return ret ? 0 : -EBUSY; +} + /* * We are generating clock pulses. ndelay() determines durating of clk pulses. * We will generate clock with rate 100 KHz and so duration of both clock levels @@ -169,21 +185,28 @@ static void set_sda_gpio_value(struct i2c_adapter *adap, int val) int i2c_generic_scl_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - int i = 0, val = 1, ret = 0; + int i = 0, scl = 1, ret; if (bri->prepare_recovery) bri->prepare_recovery(adap); - bri->set_scl(adap, val); + /* + * If we can set SDA, we will always create a STOP to ensure additional + * pulses will do no harm. This is achieved by letting SDA follow SCL + * half a cycle later. Check the 'incomplete_write_byte' fault injector + * for details. + */ + bri->set_scl(adap, scl); + ndelay(RECOVERY_NDELAY / 2); if (bri->set_sda) - bri->set_sda(adap, 1); - ndelay(RECOVERY_NDELAY); + bri->set_sda(adap, scl); + ndelay(RECOVERY_NDELAY / 2); /* * By this time SCL is high, as we need to give 9 falling-rising edges */ while (i++ < RECOVERY_CLK_CNT * 2) { - if (val) { + if (scl) { /* SCL shouldn't be low here */ if (!bri->get_scl(adap)) { dev_err(&adap->dev, @@ -191,41 +214,27 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap) ret = -EBUSY; break; } - /* Break if SDA is high */ - if (bri->get_sda && bri->get_sda(adap)) - break; } - val = !val; - bri->set_scl(adap, val); - - /* - * If we can set SDA, we will always create STOP here to ensure - * the additional pulses will do no harm. This is achieved by - * letting SDA follow SCL half a cycle later. - */ + scl = !scl; + bri->set_scl(adap, scl); + /* Creating STOP again, see above */ ndelay(RECOVERY_NDELAY / 2); if (bri->set_sda) - bri->set_sda(adap, val); + bri->set_sda(adap, scl); ndelay(RECOVERY_NDELAY / 2); - } - - /* check if recovery actually succeeded */ - if (bri->get_sda && !bri->get_sda(adap)) - ret = -EBUSY; - /* If all went well, send STOP for a sane bus state. */ - if (ret == 0 && bri->set_sda) { - bri->set_scl(adap, 0); - ndelay(RECOVERY_NDELAY / 2); - bri->set_sda(adap, 0); - ndelay(RECOVERY_NDELAY / 2); - bri->set_scl(adap, 1); - ndelay(RECOVERY_NDELAY / 2); - bri->set_sda(adap, 1); - ndelay(RECOVERY_NDELAY / 2); + if (scl) { + ret = i2c_generic_bus_free(adap); + if (ret == 0) + break; + } } + /* If we can't check bus status, assume recovery worked */ + if (ret == -EOPNOTSUPP) + ret = 0; + if (bri->unprepare_recovery) bri->unprepare_recovery(adap); @@ -274,6 +283,10 @@ static void i2c_init_recovery(struct i2c_adapter *adap) err_str = "no {get|set}_scl() found"; goto err; } + if (!bri->set_sda && !bri->get_sda) { + err_str = "either get_sda() or set_sda() needed"; + goto err; + } } return; @@ -1111,15 +1124,6 @@ static int i2c_do_add_adapter(struct i2c_driver *driver, /* Detect supported devices on that bus, and instantiate them */ i2c_detect(adap, driver); - /* Let legacy drivers scan this bus for matching devices */ - if (driver->attach_adapter) { - dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n", - driver->driver.name); - dev_warn(&adap->dev, - "Please use another way to instantiate your i2c_client\n"); - /* We ignore the return code; if it fails, too bad */ - driver->attach_adapter(adap); - } return 0; } @@ -1563,6 +1567,8 @@ void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_de ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns); if (ret && use_defaults) t->sda_fall_ns = t->scl_fall_ns; + + device_property_read_u32(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns); } EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); @@ -1826,9 +1832,15 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, if (msgs[i].flags & I2C_M_RD) { if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len)) return i2c_quirk_error(adap, &msgs[i], "msg too long"); + + if (q->flags & I2C_AQ_NO_ZERO_LEN_READ && len == 0) + return i2c_quirk_error(adap, &msgs[i], "no zero length"); } else { if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len)) return i2c_quirk_error(adap, &msgs[i], "msg too long"); + + if (q->flags & I2C_AQ_NO_ZERO_LEN_WRITE && len == 0) + return i2c_quirk_error(adap, &msgs[i], "no zero length"); } } diff --git a/drivers/i2c/i2c-core-slave.c b/drivers/i2c/i2c-core-slave.c index 4a78c65e9971..47a9f70a24a9 100644 --- a/drivers/i2c/i2c-core-slave.c +++ b/drivers/i2c/i2c-core-slave.c @@ -47,9 +47,9 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) client->slave_cb = slave_cb; - i2c_lock_adapter(client->adapter); + i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER); ret = client->adapter->algo->reg_slave(client); - i2c_unlock_adapter(client->adapter); + i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER); if (ret) { client->slave_cb = NULL; @@ -69,9 +69,9 @@ int i2c_slave_unregister(struct i2c_client *client) return -EOPNOTSUPP; } - i2c_lock_adapter(client->adapter); + i2c_lock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER); ret = client->adapter->algo->unreg_slave(client); - i2c_unlock_adapter(client->adapter); + i2c_unlock_bus(client->adapter, I2C_LOCK_ROOT_ADAPTER); if (ret == 0) client->slave_cb = NULL; diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 29646aa6132e..f330690b4125 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -87,8 +87,8 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap, ret = muxc->select(muxc, priv->chan_id); if (ret >= 0) - ret = parent->algo->smbus_xfer(parent, addr, flags, - read_write, command, size, data); + ret = __i2c_smbus_xfer(parent, addr, flags, + read_write, command, size, data); if (muxc->deselect) muxc->deselect(muxc, priv->chan_id); diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 12ad8d65faf6..f2bf3e57ed67 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -94,31 +94,11 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, struct i2c_client *client, u8 val) { struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); - int ret = -ENODEV; - - if (adap->algo->master_xfer) { - struct i2c_msg msg; - u8 msgbuf[] = {pdata->sel_reg_addr, val}; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2; - msg.buf = msgbuf; - ret = __i2c_transfer(adap, &msg, 1); - - if (ret >= 0 && ret != 1) - ret = -EREMOTEIO; - } else if (adap->algo->smbus_xfer) { - union i2c_smbus_data data; - - data.byte = val; - ret = adap->algo->smbus_xfer(adap, client->addr, - client->flags, I2C_SMBUS_WRITE, - pdata->sel_reg_addr, - I2C_SMBUS_BYTE_DATA, &data); - } + union i2c_smbus_data data = { .byte = val }; - return ret; + return __i2c_smbus_xfer(adap, client->addr, client->flags, + I2C_SMBUS_WRITE, pdata->sel_reg_addr, + I2C_SMBUS_BYTE_DATA, &data); } static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 6a39adaf433f..9e75d6b9140b 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -99,31 +99,11 @@ MODULE_DEVICE_TABLE(of, pca9541_of_match); static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) { struct i2c_adapter *adap = client->adapter; - int ret; - - if (adap->algo->master_xfer) { - struct i2c_msg msg; - char buf[2]; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2; - buf[0] = command; - buf[1] = val; - msg.buf = buf; - ret = __i2c_transfer(adap, &msg, 1); - } else { - union i2c_smbus_data data; - - data.byte = val; - ret = adap->algo->smbus_xfer(adap, client->addr, - client->flags, - I2C_SMBUS_WRITE, - command, - I2C_SMBUS_BYTE_DATA, &data); - } + union i2c_smbus_data data = { .byte = val }; - return ret; + return __i2c_smbus_xfer(adap, client->addr, client->flags, + I2C_SMBUS_WRITE, command, + I2C_SMBUS_BYTE_DATA, &data); } /* @@ -133,41 +113,14 @@ static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val) static int pca9541_reg_read(struct i2c_client *client, u8 command) { struct i2c_adapter *adap = client->adapter; + union i2c_smbus_data data; int ret; - u8 val; - - if (adap->algo->master_xfer) { - struct i2c_msg msg[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &command - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 1, - .buf = &val - } - }; - ret = __i2c_transfer(adap, msg, 2); - if (ret == 2) - ret = val; - else if (ret >= 0) - ret = -EIO; - } else { - union i2c_smbus_data data; - - ret = adap->algo->smbus_xfer(adap, client->addr, - client->flags, - I2C_SMBUS_READ, - command, - I2C_SMBUS_BYTE_DATA, &data); - if (!ret) - ret = data.byte; - } - return ret; + + ret = __i2c_smbus_xfer(adap, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_BYTE_DATA, &data); + + return ret ?: data.byte; } /* @@ -345,11 +298,11 @@ static int pca9541_probe(struct i2c_client *client, /* * I2C accesses are unprotected here. - * We have to lock the adapter before releasing the bus. + * We have to lock the I2C segment before releasing the bus. */ - i2c_lock_adapter(adap); + i2c_lock_bus(adap, I2C_LOCK_SEGMENT); pca9541_release_bus(client); - i2c_unlock_adapter(adap); + i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); /* Create mux adapter */ diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index fbc748027087..24bd9275fde5 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -220,30 +220,11 @@ MODULE_DEVICE_TABLE(of, pca954x_of_match); static int pca954x_reg_write(struct i2c_adapter *adap, struct i2c_client *client, u8 val) { - int ret = -ENODEV; - - if (adap->algo->master_xfer) { - struct i2c_msg msg; - char buf[1]; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 1; - buf[0] = val; - msg.buf = buf; - ret = __i2c_transfer(adap, &msg, 1); - - if (ret >= 0 && ret != 1) - ret = -EREMOTEIO; - } else { - union i2c_smbus_data data; - ret = adap->algo->smbus_xfer(adap, client->addr, - client->flags, - I2C_SMBUS_WRITE, - val, I2C_SMBUS_BYTE, &data); - } + union i2c_smbus_data dummy; - return ret; + return __i2c_smbus_xfer(adap, client->addr, client->flags, + I2C_SMBUS_WRITE, val, + I2C_SMBUS_BYTE, &dummy); } static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) @@ -368,7 +349,8 @@ static int pca954x_probe(struct i2c_client *client, { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *of_node = client->dev.of_node; + struct device *dev = &client->dev; + struct device_node *np = dev->of_node; bool idle_disconnect_dt; struct gpio_desc *gpio; int num, force, class; @@ -379,8 +361,7 @@ static int pca954x_probe(struct i2c_client *client, if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) return -ENODEV; - muxc = i2c_mux_alloc(adap, &client->dev, - PCA954X_MAX_NCHANS, sizeof(*data), 0, + muxc = i2c_mux_alloc(adap, dev, PCA954X_MAX_NCHANS, sizeof(*data), 0, pca954x_select_chan, pca954x_deselect_mux); if (!muxc) return -ENOMEM; @@ -390,7 +371,7 @@ static int pca954x_probe(struct i2c_client *client, data->client = client; /* Reset the mux if a reset GPIO is specified. */ - gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); + gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) return PTR_ERR(gpio); if (gpio) { @@ -400,7 +381,7 @@ static int pca954x_probe(struct i2c_client *client, udelay(1); } - data->chip = of_device_get_match_data(&client->dev); + data->chip = of_device_get_match_data(dev); if (!data->chip) data->chip = &chips[id->driver_data]; @@ -414,8 +395,7 @@ static int pca954x_probe(struct i2c_client *client, if (!ret && (id.manufacturer_id != data->chip->id.manufacturer_id || id.part_id != data->chip->id.part_id)) { - dev_warn(&client->dev, - "unexpected device id %03x-%03x-%x\n", + dev_warn(dev, "unexpected device id %03x-%03x-%x\n", id.manufacturer_id, id.part_id, id.die_revision); return -ENODEV; @@ -427,14 +407,14 @@ static int pca954x_probe(struct i2c_client *client, * initializes the mux to disconnected state. */ if (i2c_smbus_write_byte(client, 0) < 0) { - dev_warn(&client->dev, "probe failed\n"); + dev_warn(dev, "probe failed\n"); return -ENODEV; } data->last_chan = 0; /* force the first selection */ - idle_disconnect_dt = of_node && - of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); + idle_disconnect_dt = np && + of_property_read_bool(np, "i2c-mux-idle-disconnect"); ret = pca954x_irq_setup(muxc); if (ret) @@ -465,7 +445,7 @@ static int pca954x_probe(struct i2c_client *client, } if (data->irq) { - ret = devm_request_threaded_irq(&client->dev, data->client->irq, + ret = devm_request_threaded_irq(dev, data->client->irq, NULL, pca954x_irq_handler, IRQF_ONESHOT | IRQF_SHARED, "pca954x", data); @@ -473,8 +453,7 @@ static int pca954x_probe(struct i2c_client *client, goto fail_cleanup; } - dev_info(&client->dev, - "registered %d multiplexed busses for I2C %s %s\n", + dev_info(dev, "registered %d multiplexed busses for I2C %s %s\n", num, data->chip->muxtype == pca954x_ismux ? "mux" : "switch", client->name); diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index e52c58c29d9a..4d565b0c5a6e 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -574,13 +574,14 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive) if (!HPT370_ALLOW_ATA100_5 || check_in_drive_list(drive, bad_ata100_5)) return ATA_UDMA4; + /* else: fall through */ case HPT372 : case HPT372A: case HPT372N: case HPT374 : if (ata_id_is_sata(drive->id)) mask &= ~0x0e; - /* Fall thru */ + /* fall through */ default: return mask; } @@ -600,7 +601,7 @@ static u8 hpt3xx_mdma_filter(ide_drive_t *drive) case HPT374 : if (ata_id_is_sata(drive->id)) return 0x00; - /* Fall thru */ + /* else: fall through */ default: return 0x07; } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 5bd2aafc3753..a8df300f949c 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -427,6 +427,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) * (maintains previous driver behaviour) */ break; + /* else: fall through */ case CAPACITY_CURRENT: /* Normal Zip/LS-120 disks */ if (memcmp(cap_desc, &floppy->cap_desc, 8)) diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index a444bad7a2aa..0d93e0cfbeaf 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -460,7 +460,6 @@ void do_ide_request(struct request_queue *q) struct ide_host *host = hwif->host; struct request *rq = NULL; ide_startstop_t startstop; - unsigned long queue_run_ms = 3; /* old plug delay */ spin_unlock_irq(q->queue_lock); @@ -480,9 +479,6 @@ repeat: prev_port = hwif->host->cur_port; if (drive->dev_flags & IDE_DFLAG_SLEEPING && time_after(drive->sleep, jiffies)) { - unsigned long left = jiffies - drive->sleep; - - queue_run_ms = jiffies_to_msecs(left + 1); ide_unlock_port(hwif); goto plug_device; } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 416a2f353071..3b75a7b7a284 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -142,6 +142,7 @@ static void ide_classify_atapi_dev(ide_drive_t *drive) } /* Early cdrom models used zero */ type = ide_cdrom; + /* fall through */ case ide_cdrom: drive->dev_flags |= IDE_DFLAG_REMOVABLE; #ifdef CONFIG_PPC diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index aee7b46d2330..34c1165226a4 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1746,7 +1746,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) { unsigned long t; int speed; - int buffer_size; u16 *ctl = (u16 *)&tape->caps[12]; ide_debug_log(IDE_DBG_FUNC, "minor: %d", minor); @@ -1781,7 +1780,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) *ctl /= 2; tape->buffer_size = *ctl * tape->blk_size; } - buffer_size = tape->buffer_size; /* select the "best" DSC read/write polling freq */ speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 89b29028d315..c21d5c50ae3a 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -128,7 +128,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) return pre_task_out_intr(drive, cmd); } handler = task_pio_intr; - /* fall-through */ + /* fall through */ case ATA_PROT_NODATA: if (handler == NULL) handler = task_no_data_intr; @@ -140,6 +140,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) hwif->expiry = dma_ops->dma_timer_expiry; ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD); dma_ops->dma_start(drive); + /* fall through */ default: return ide_started; } diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c index c3062b53056f..024bc7ba49ee 100644 --- a/drivers/ide/sis5513.c +++ b/drivers/ide/sis5513.c @@ -494,6 +494,7 @@ static int init_chipset_sis5513(struct pci_dev *dev) pci_read_config_byte(dev, 0x09, ®); if ((reg & 0x0f) != 0x00) pci_write_config_byte(dev, 0x09, reg&0xf0); + /* fall through */ case ATA_16: /* force per drive recovery and active timings needed on ATA_33 and below chips */ diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c index 28e9b7656b20..15d498fc4758 100644 --- a/drivers/iio/dac/ltc2632.c +++ b/drivers/iio/dac/ltc2632.c @@ -1,7 +1,7 @@ /* * LTC2632 Digital to analog convertors spi driver * - * Copyright 2017 Maxime Roussin-Bélanger + * Copyright 2017 Maxime Roussin-Bélanger * expanded by Silvan Murer <silvan.murer@gmail.com> * * Licensed under the GPL-2. diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index d619e8634a00..13a4cec64ea8 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -433,11 +433,11 @@ static int mlx90614_wakeup(struct mlx90614_data *data) dev_dbg(&data->client->dev, "Requesting wake-up"); - i2c_lock_adapter(data->client->adapter); + i2c_lock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); gpiod_direction_output(data->wakeup_gpio, 0); msleep(MLX90614_TIMING_WAKEUP); gpiod_direction_input(data->wakeup_gpio); - i2c_unlock_adapter(data->client->adapter); + i2c_unlock_bus(data->client->adapter, I2C_LOCK_ROOT_ADAPTER); data->ready_timestamp = jiffies + msecs_to_jiffies(MLX90614_TIMING_STARTUP); diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index d160d2d1f3a3..abb6660c099c 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -36,7 +36,7 @@ config INFINIBAND_USER_ACCESS rdma-core <https://github.com/linux-rdma/rdma-core>. config INFINIBAND_USER_ACCESS_UCM - bool "Userspace CM (UCM, DEPRECATED)" + tristate "Userspace CM (UCM, DEPRECATED)" depends on BROKEN || COMPILE_TEST depends on INFINIBAND_USER_ACCESS help diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 182436b92ba9..6ec748eccff7 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -186,6 +186,7 @@ static void ib_umem_notifier_release(struct mmu_notifier *mn, rbt_ib_umem_for_each_in_range(&context->umem_tree, 0, ULLONG_MAX, ib_umem_notifier_release_trampoline, + true, NULL); up_read(&context->umem_rwsem); } @@ -207,22 +208,31 @@ static int invalidate_range_start_trampoline(struct ib_umem *item, u64 start, return 0; } -static void ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn, +static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end, + bool blockable) { struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn); + int ret; if (!context->invalidate_range) - return; + return 0; + + if (blockable) + down_read(&context->umem_rwsem); + else if (!down_read_trylock(&context->umem_rwsem)) + return -EAGAIN; ib_ucontext_notifier_start_account(context); - down_read(&context->umem_rwsem); - rbt_ib_umem_for_each_in_range(&context->umem_tree, start, + ret = rbt_ib_umem_for_each_in_range(&context->umem_tree, start, end, - invalidate_range_start_trampoline, NULL); + invalidate_range_start_trampoline, + blockable, NULL); up_read(&context->umem_rwsem); + + return ret; } static int invalidate_range_end_trampoline(struct ib_umem *item, u64 start, @@ -242,10 +252,15 @@ static void ib_umem_notifier_invalidate_range_end(struct mmu_notifier *mn, if (!context->invalidate_range) return; + /* + * TODO: we currently bail out if there is any sleepable work to be done + * in ib_umem_notifier_invalidate_range_start so we shouldn't really block + * here. But this is ugly and fragile. + */ down_read(&context->umem_rwsem); rbt_ib_umem_for_each_in_range(&context->umem_tree, start, end, - invalidate_range_end_trampoline, NULL); + invalidate_range_end_trampoline, true, NULL); up_read(&context->umem_rwsem); ib_ucontext_notifier_end_account(context); } @@ -798,6 +813,7 @@ EXPORT_SYMBOL(ib_umem_odp_unmap_dma_pages); int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root, u64 start, u64 last, umem_call_back cb, + bool blockable, void *cookie) { int ret_val = 0; @@ -809,6 +825,9 @@ int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root, for (node = rbt_ib_umem_iter_first(root, start, last - 1); node; node = next) { + /* TODO move the blockable decision up to the callback */ + if (!blockable) + return -EAGAIN; next = rbt_ib_umem_iter_next(node, start, last - 1); umem = container_of(node, struct ib_umem_odp, interval_tree); ret_val = cb(umem->umem, start, last, cookie) || ret_val; diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c index fbe7198a715a..bedd5fba33b0 100644 --- a/drivers/infiniband/hw/hfi1/affinity.c +++ b/drivers/infiniband/hw/hfi1/affinity.c @@ -198,7 +198,7 @@ int node_affinity_init(void) while ((dev = pci_get_device(ids->vendor, ids->device, dev))) { node = pcibus_to_node(dev->bus); if (node < 0) - node = numa_node_id(); + goto out; hfi1_per_node_cntr[node]++; } @@ -206,6 +206,18 @@ int node_affinity_init(void) } return 0; + +out: + /* + * Invalid PCI NUMA node information found, note it, and populate + * our database 1:1. + */ + pr_err("HFI: Invalid PCI NUMA node. Performance may be affected\n"); + pr_err("HFI: System BIOS may need to be upgraded\n"); + for (node = 0; node < node_affinity.num_possible_nodes; node++) + hfi1_per_node_cntr[node] = 1; + + return 0; } static void node_affinity_destroy(struct hfi1_affinity_node *entry) @@ -622,8 +634,14 @@ int hfi1_dev_affinity_init(struct hfi1_devdata *dd) int curr_cpu, possible, i, ret; bool new_entry = false; - if (node < 0) - node = numa_node_id(); + /* + * If the BIOS does not have the NUMA node information set, select + * NUMA 0 so we get consistent performance. + */ + if (node < 0) { + dd_dev_err(dd, "Invalid PCI NUMA node. Performance may be affected\n"); + node = 0; + } dd->node = node; local_mask = cpumask_of_node(dd->node); diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.c b/drivers/infiniband/hw/hfi1/mmu_rb.c index 70aceefe14d5..e1c7996c018e 100644 --- a/drivers/infiniband/hw/hfi1/mmu_rb.c +++ b/drivers/infiniband/hw/hfi1/mmu_rb.c @@ -67,9 +67,9 @@ struct mmu_rb_handler { static unsigned long mmu_node_start(struct mmu_rb_node *); static unsigned long mmu_node_last(struct mmu_rb_node *); -static void mmu_notifier_range_start(struct mmu_notifier *, +static int mmu_notifier_range_start(struct mmu_notifier *, struct mm_struct *, - unsigned long, unsigned long); + unsigned long, unsigned long, bool); static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *, unsigned long, unsigned long); static void do_remove(struct mmu_rb_handler *handler, @@ -284,10 +284,11 @@ void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler, handler->ops->remove(handler->ops_arg, node); } -static void mmu_notifier_range_start(struct mmu_notifier *mn, +static int mmu_notifier_range_start(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end, + bool blockable) { struct mmu_rb_handler *handler = container_of(mn, struct mmu_rb_handler, mn); @@ -313,6 +314,8 @@ static void mmu_notifier_range_start(struct mmu_notifier *mn, if (added) queue_work(handler->wq, &handler->del_work); + + return 0; } /* diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index f1a87a690a4c..d216e0d2921d 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -488,7 +488,7 @@ void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr) down_read(&ctx->umem_rwsem); rbt_ib_umem_for_each_in_range(&ctx->umem_tree, 0, ULLONG_MAX, - mr_leaf_free, imr); + mr_leaf_free, true, imr); up_read(&ctx->umem_rwsem); wait_event(imr->q_leaf_free, !atomic_read(&imr->num_leaf_free)); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 6bd97ffee761..4713957b0cbb 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -721,7 +721,7 @@ config KEYBOARD_CROS_EC help Say Y here to enable the matrix keyboard used by ChromeOS devices and implemented on the ChromeOS EC. You must enable one bus option - (MFD_CROS_EC_I2C or MFD_CROS_EC_SPI) to use this. + (CROS_EC_I2C or CROS_EC_SPI) to use this. To compile this driver as a module, choose M here: the module will be called cros_ec_keyb. diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index 3df501c3421b..f8663d7891f2 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -20,32 +20,33 @@ * However, when used with the E3 mailboard that producecs non-standard * scancodes, a custom key table must be prepared and loaded from userspace. */ -#include <linux/gpio.h> #include <linux/irq.h> +#include <linux/platform_data/ams-delta-fiq.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/serio.h> #include <linux/slab.h> #include <linux/module.h> -#include <asm/mach-types.h> -#include <mach/board-ams-delta.h> - -#include <mach/ams-delta-fiq.h> +#define DRIVER_NAME "ams-delta-serio" MODULE_AUTHOR("Matt Callow"); MODULE_DESCRIPTION("AMS Delta (E3) keyboard port driver"); MODULE_LICENSE("GPL"); -static struct serio *ams_delta_serio; +struct ams_delta_serio { + struct serio *serio; + struct regulator *vcc; + unsigned int *fiq_buffer; +}; -static int check_data(int data) +static int check_data(struct serio *serio, int data) { int i, parity = 0; /* check valid stop bit */ if (!(data & 0x400)) { - dev_warn(&ams_delta_serio->dev, - "invalid stop bit, data=0x%X\n", - data); + dev_warn(&serio->dev, "invalid stop bit, data=0x%X\n", data); return SERIO_FRAME; } /* calculate the parity */ @@ -55,9 +56,9 @@ static int check_data(int data) } /* it should be odd */ if (!(parity & 0x01)) { - dev_warn(&ams_delta_serio->dev, - "parity check failed, data=0x%X parity=0x%X\n", - data, parity); + dev_warn(&serio->dev, + "parity check failed, data=0x%X parity=0x%X\n", data, + parity); return SERIO_PARITY; } return 0; @@ -65,127 +66,130 @@ static int check_data(int data) static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id) { - int *circ_buff = &fiq_buffer[FIQ_CIRC_BUFF]; + struct ams_delta_serio *priv = dev_id; + int *circ_buff = &priv->fiq_buffer[FIQ_CIRC_BUFF]; int data, dfl; u8 scancode; - fiq_buffer[FIQ_IRQ_PEND] = 0; + priv->fiq_buffer[FIQ_IRQ_PEND] = 0; /* * Read data from the circular buffer, check it * and then pass it on the serio */ - while (fiq_buffer[FIQ_KEYS_CNT] > 0) { + while (priv->fiq_buffer[FIQ_KEYS_CNT] > 0) { - data = circ_buff[fiq_buffer[FIQ_HEAD_OFFSET]++]; - fiq_buffer[FIQ_KEYS_CNT]--; - if (fiq_buffer[FIQ_HEAD_OFFSET] == fiq_buffer[FIQ_BUF_LEN]) - fiq_buffer[FIQ_HEAD_OFFSET] = 0; + data = circ_buff[priv->fiq_buffer[FIQ_HEAD_OFFSET]++]; + priv->fiq_buffer[FIQ_KEYS_CNT]--; + if (priv->fiq_buffer[FIQ_HEAD_OFFSET] == + priv->fiq_buffer[FIQ_BUF_LEN]) + priv->fiq_buffer[FIQ_HEAD_OFFSET] = 0; - dfl = check_data(data); + dfl = check_data(priv->serio, data); scancode = (u8) (data >> 1) & 0xFF; - serio_interrupt(ams_delta_serio, scancode, dfl); + serio_interrupt(priv->serio, scancode, dfl); } return IRQ_HANDLED; } static int ams_delta_serio_open(struct serio *serio) { - /* enable keyboard */ - gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 1); + struct ams_delta_serio *priv = serio->port_data; - return 0; + /* enable keyboard */ + return regulator_enable(priv->vcc); } static void ams_delta_serio_close(struct serio *serio) { + struct ams_delta_serio *priv = serio->port_data; + /* disable keyboard */ - gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 0); + regulator_disable(priv->vcc); } -static const struct gpio ams_delta_gpios[] __initconst_or_module = { - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_DATA, - .flags = GPIOF_DIR_IN, - .label = "serio-data", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_CLK, - .flags = GPIOF_DIR_IN, - .label = "serio-clock", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_PWR, - .flags = GPIOF_OUT_INIT_LOW, - .label = "serio-power", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT, - .flags = GPIOF_OUT_INIT_LOW, - .label = "serio-dataout", - }, -}; - -static int __init ams_delta_serio_init(void) +static int ams_delta_serio_init(struct platform_device *pdev) { - int err; - - if (!machine_is_ams_delta()) - return -ENODEV; + struct ams_delta_serio *priv; + struct serio *serio; + int irq, err; - ams_delta_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); - if (!ams_delta_serio) + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - ams_delta_serio->id.type = SERIO_8042; - ams_delta_serio->open = ams_delta_serio_open; - ams_delta_serio->close = ams_delta_serio_close; - strlcpy(ams_delta_serio->name, "AMS DELTA keyboard adapter", - sizeof(ams_delta_serio->name)); - strlcpy(ams_delta_serio->phys, "GPIO/serio0", - sizeof(ams_delta_serio->phys)); - - err = gpio_request_array(ams_delta_gpios, - ARRAY_SIZE(ams_delta_gpios)); - if (err) { - pr_err("ams_delta_serio: Couldn't request gpio pins\n"); - goto serio; + priv->fiq_buffer = pdev->dev.platform_data; + if (!priv->fiq_buffer) + return -EINVAL; + + priv->vcc = devm_regulator_get(&pdev->dev, "vcc"); + if (IS_ERR(priv->vcc)) { + err = PTR_ERR(priv->vcc); + dev_err(&pdev->dev, "regulator request failed (%d)\n", err); + /* + * When running on a non-dt platform and requested regulator + * is not available, devm_regulator_get() never returns + * -EPROBE_DEFER as it is not able to justify if the regulator + * may still appear later. On the other hand, the board can + * still set full constriants flag at late_initcall in order + * to instruct devm_regulator_get() to returnn a dummy one + * if sufficient. Hence, if we get -ENODEV here, let's convert + * it to -EPROBE_DEFER and wait for the board to decide or + * let Deferred Probe infrastructure handle this error. + */ + if (err == -ENODEV) + err = -EPROBE_DEFER; + return err; } - err = request_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), - ams_delta_serio_interrupt, IRQ_TYPE_EDGE_RISING, - "ams-delta-serio", 0); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENXIO; + + err = devm_request_irq(&pdev->dev, irq, ams_delta_serio_interrupt, + IRQ_TYPE_EDGE_RISING, DRIVER_NAME, priv); if (err < 0) { - pr_err("ams_delta_serio: couldn't request gpio interrupt %d\n", - gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK)); - goto gpio; + dev_err(&pdev->dev, "IRQ request failed (%d)\n", err); + return err; } - /* - * Since GPIO register handling for keyboard clock pin is performed - * at FIQ level, switch back from edge to simple interrupt handler - * to avoid bad interaction. - */ - irq_set_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), - handle_simple_irq); - serio_register_port(ams_delta_serio); - dev_info(&ams_delta_serio->dev, "%s\n", ams_delta_serio->name); + serio = kzalloc(sizeof(*serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + priv->serio = serio; + + serio->id.type = SERIO_8042; + serio->open = ams_delta_serio_open; + serio->close = ams_delta_serio_close; + strlcpy(serio->name, "AMS DELTA keyboard adapter", sizeof(serio->name)); + strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys)); + serio->dev.parent = &pdev->dev; + serio->port_data = priv; + + serio_register_port(serio); + + platform_set_drvdata(pdev, priv); + + dev_info(&serio->dev, "%s\n", serio->name); return 0; -gpio: - gpio_free_array(ams_delta_gpios, - ARRAY_SIZE(ams_delta_gpios)); -serio: - kfree(ams_delta_serio); - return err; } -module_init(ams_delta_serio_init); -static void __exit ams_delta_serio_exit(void) +static int ams_delta_serio_exit(struct platform_device *pdev) { - serio_unregister_port(ams_delta_serio); - free_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0); - gpio_free_array(ams_delta_gpios, - ARRAY_SIZE(ams_delta_gpios)); + struct ams_delta_serio *priv = platform_get_drvdata(pdev); + + serio_unregister_port(priv->serio); + + return 0; } -module_exit(ams_delta_serio_exit); + +static struct platform_driver ams_delta_serio_driver = { + .probe = ams_delta_serio_init, + .remove = ams_delta_serio_exit, + .driver = { + .name = DRIVER_NAME + }, +}; +module_platform_driver(ams_delta_serio_driver); diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index bda0500c9b57..714affdd742f 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -304,7 +304,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, msg[1].len = len; msg[1].buf = buf; - i2c_lock_adapter(adap); + i2c_lock_bus(adap, I2C_LOCK_SEGMENT); for (i = 0; i < 2; i++) { if (__i2c_transfer(adap, &msg[i], 1) < 0) { @@ -313,7 +313,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, } } - i2c_unlock_adapter(adap); + i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); return ret; } diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 689ffe538370..c60395b7470f 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -60,6 +60,27 @@ config IOMMU_IO_PGTABLE_ARMV7S_SELFTEST endmenu +config IOMMU_DEBUGFS + bool "Export IOMMU internals in DebugFS" + depends on DEBUG_FS + help + Allows exposure of IOMMU device internals. This option enables + the use of debugfs by IOMMU drivers as required. Devices can, + at initialization time, cause the IOMMU code to create a top-level + debug/iommu directory, and then populate a subdirectory with + entries as required. + +config IOMMU_DEFAULT_PASSTHROUGH + bool "IOMMU passthrough by default" + depends on IOMMU_API + help + Enable passthrough by default, removing the need to pass in + iommu.passthrough=on or iommu=pt through command line. If this + is enabled, you can still disable with iommu.passthrough=off + or iommu=nopt depending on the architecture. + + If unsure, say N here. + config IOMMU_IOVA tristate @@ -135,6 +156,18 @@ config AMD_IOMMU_V2 hardware. Select this option if you want to use devices that support the PCI PRI and PASID interface. +config AMD_IOMMU_DEBUGFS + bool "Enable AMD IOMMU internals in DebugFS" + depends on AMD_IOMMU && IOMMU_DEBUGFS + ---help--- + !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! + + DO NOT ENABLE THIS OPTION UNLESS YOU REALLY, -REALLY- KNOW WHAT YOU ARE DOING!!! + Exposes AMD IOMMU device internals in DebugFS. + + This option is -NOT- intended for production environments, and should + not generally be enabled. + # Intel IOMMU support config DMAR_TABLE bool @@ -284,8 +317,8 @@ config IPMMU_VMSA select IOMMU_IO_PGTABLE_LPAE select ARM_DMA_USE_IOMMU help - Support for the Renesas VMSA-compatible IPMMU Renesas found in the - R-Mobile APE6 and R-Car H2/M2 SoCs. + Support for the Renesas VMSA-compatible IPMMU found in the R-Mobile + APE6, R-Car Gen2, and R-Car Gen3 SoCs. If unsure, say N. diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 1fb695854809..ab5eba6edf82 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_IOMMU_API) += iommu.o obj-$(CONFIG_IOMMU_API) += iommu-traces.o obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o +obj-$(CONFIG_IOMMU_DEBUGFS) += iommu-debugfs.o obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o @@ -10,11 +11,12 @@ obj-$(CONFIG_IOMMU_IOVA) += iova.o obj-$(CONFIG_OF_IOMMU) += of_iommu.o obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o +obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd_iommu_debugfs.o obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o obj-$(CONFIG_ARM_SMMU) += arm-smmu.o obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o obj-$(CONFIG_DMAR_TABLE) += dmar.o -obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o +obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 60b2eab29cd8..4e04fff23977 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -1404,6 +1404,8 @@ static u64 *fetch_pte(struct protection_domain *domain, int level; u64 *pte; + *page_size = 0; + if (address > PM_LEVEL_SIZE(domain->mode)) return NULL; @@ -1944,12 +1946,6 @@ static int __attach_device(struct iommu_dev_data *dev_data, { int ret; - /* - * Must be called with IRQs disabled. Warn here to detect early - * when its not. - */ - WARN_ON(!irqs_disabled()); - /* lock domain */ spin_lock(&domain->lock); @@ -2115,12 +2111,6 @@ static void __detach_device(struct iommu_dev_data *dev_data) { struct protection_domain *domain; - /* - * Must be called with IRQs disabled. Warn here to detect early - * when its not. - */ - WARN_ON(!irqs_disabled()); - domain = dev_data->domain; spin_lock(&domain->lock); @@ -2405,9 +2395,9 @@ static void __unmap_single(struct dma_ops_domain *dma_dom, } if (amd_iommu_unmap_flush) { - dma_ops_free_iova(dma_dom, dma_addr, pages); domain_flush_tlb(&dma_dom->domain); domain_flush_complete(&dma_dom->domain); + dma_ops_free_iova(dma_dom, dma_addr, pages); } else { pages = __roundup_pow_of_two(pages); queue_iova(&dma_dom->iovad, dma_addr >> PAGE_SHIFT, pages, 0); @@ -3192,7 +3182,6 @@ const struct iommu_ops amd_iommu_ops = { .detach_dev = amd_iommu_detach_device, .map = amd_iommu_map, .unmap = amd_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = amd_iommu_iova_to_phys, .add_device = amd_iommu_add_device, .remove_device = amd_iommu_remove_device, @@ -3874,7 +3863,8 @@ static void irte_ga_prepare(void *entry, irte->lo.fields_remap.int_type = delivery_mode; irte->lo.fields_remap.dm = dest_mode; irte->hi.fields.vector = vector; - irte->lo.fields_remap.destination = dest_apicid; + irte->lo.fields_remap.destination = APICID_TO_IRTE_DEST_LO(dest_apicid); + irte->hi.fields.destination = APICID_TO_IRTE_DEST_HI(dest_apicid); irte->lo.fields_remap.valid = 1; } @@ -3927,7 +3917,10 @@ static void irte_ga_set_affinity(void *entry, u16 devid, u16 index, if (!irte->lo.fields_remap.guest_mode) { irte->hi.fields.vector = vector; - irte->lo.fields_remap.destination = dest_apicid; + irte->lo.fields_remap.destination = + APICID_TO_IRTE_DEST_LO(dest_apicid); + irte->hi.fields.destination = + APICID_TO_IRTE_DEST_HI(dest_apicid); modify_irte_ga(devid, index, irte, NULL); } } @@ -4344,7 +4337,10 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) irte->lo.val = 0; irte->hi.fields.vector = cfg->vector; irte->lo.fields_remap.guest_mode = 0; - irte->lo.fields_remap.destination = cfg->dest_apicid; + irte->lo.fields_remap.destination = + APICID_TO_IRTE_DEST_LO(cfg->dest_apicid); + irte->hi.fields.destination = + APICID_TO_IRTE_DEST_HI(cfg->dest_apicid); irte->lo.fields_remap.int_type = apic->irq_delivery_mode; irte->lo.fields_remap.dm = apic->irq_dest_mode; @@ -4461,8 +4457,12 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data) raw_spin_lock_irqsave(&table->lock, flags); if (ref->lo.fields_vapic.guest_mode) { - if (cpu >= 0) - ref->lo.fields_vapic.destination = cpu; + if (cpu >= 0) { + ref->lo.fields_vapic.destination = + APICID_TO_IRTE_DEST_LO(cpu); + ref->hi.fields.destination = + APICID_TO_IRTE_DEST_HI(cpu); + } ref->lo.fields_vapic.is_run = is_run; barrier(); } diff --git a/drivers/iommu/amd_iommu_debugfs.c b/drivers/iommu/amd_iommu_debugfs.c new file mode 100644 index 000000000000..c6a5c737ef09 --- /dev/null +++ b/drivers/iommu/amd_iommu_debugfs.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD IOMMU driver + * + * Copyright (C) 2018 Advanced Micro Devices, Inc. + * + * Author: Gary R Hook <gary.hook@amd.com> + */ + +#include <linux/debugfs.h> +#include <linux/iommu.h> +#include <linux/pci.h> +#include "amd_iommu_proto.h" +#include "amd_iommu_types.h" + +static struct dentry *amd_iommu_debugfs; +static DEFINE_MUTEX(amd_iommu_debugfs_lock); + +#define MAX_NAME_LEN 20 + +void amd_iommu_debugfs_setup(struct amd_iommu *iommu) +{ + char name[MAX_NAME_LEN + 1]; + + mutex_lock(&amd_iommu_debugfs_lock); + if (!amd_iommu_debugfs) + amd_iommu_debugfs = debugfs_create_dir("amd", + iommu_debugfs_dir); + mutex_unlock(&amd_iommu_debugfs_lock); + + snprintf(name, MAX_NAME_LEN, "iommu%02d", iommu->index); + iommu->debugfs = debugfs_create_dir(name, amd_iommu_debugfs); +} diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 904c575d1677..84b3e4445d46 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -153,6 +153,7 @@ bool amd_iommu_dump; bool amd_iommu_irq_remap __read_mostly; int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC; +static int amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE; static bool amd_iommu_detected; static bool __initdata amd_iommu_disabled; @@ -280,9 +281,9 @@ static void clear_translation_pre_enabled(struct amd_iommu *iommu) static void init_translation_status(struct amd_iommu *iommu) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); if (ctrl & (1<<CONTROL_IOMMU_EN)) iommu->flags |= AMD_IOMMU_FLAG_TRANS_PRE_ENABLED; } @@ -386,30 +387,30 @@ static void iommu_set_device_table(struct amd_iommu *iommu) /* Generic functions to enable/disable certain features of the IOMMU. */ static void iommu_feature_enable(struct amd_iommu *iommu, u8 bit) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); - ctrl |= (1 << bit); - writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl |= (1ULL << bit); + writeq(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); } static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); - ctrl &= ~(1 << bit); - writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl &= ~(1ULL << bit); + writeq(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); } static void iommu_set_inv_tlb_timeout(struct amd_iommu *iommu, int timeout) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); ctrl &= ~CTRL_INV_TO_MASK; ctrl |= (timeout << CONTROL_INV_TIMEOUT) & CTRL_INV_TO_MASK; - writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); + writeq(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); } /* Function to enable the hardware */ @@ -827,6 +828,19 @@ static int iommu_init_ga(struct amd_iommu *iommu) return ret; } +static void iommu_enable_xt(struct amd_iommu *iommu) +{ +#ifdef CONFIG_IRQ_REMAP + /* + * XT mode (32-bit APIC destination ID) requires + * GA mode (128-bit IRTE support) as a prerequisite. + */ + if (AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir) && + amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE) + iommu_feature_enable(iommu, CONTROL_XT_EN); +#endif /* CONFIG_IRQ_REMAP */ +} + static void iommu_enable_gt(struct amd_iommu *iommu) { if (!iommu_feature(iommu, FEATURE_GT)) @@ -1507,6 +1521,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0)) amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; + if (((h->efr_attr & (0x1 << IOMMU_FEAT_XTSUP_SHIFT)) == 0)) + amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; break; case 0x11: case 0x40: @@ -1516,6 +1532,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; + if (((h->efr_reg & (0x1 << IOMMU_EFR_XTSUP_SHIFT)) == 0)) + amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; break; default: return -EINVAL; @@ -1832,6 +1850,8 @@ static void print_iommu_info(void) pr_info("AMD-Vi: Interrupt remapping enabled\n"); if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir)) pr_info("AMD-Vi: virtual APIC enabled\n"); + if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE) + pr_info("AMD-Vi: X2APIC enabled\n"); } } @@ -2168,6 +2188,7 @@ static void early_enable_iommu(struct amd_iommu *iommu) iommu_enable_event_buffer(iommu); iommu_set_exclusion_range(iommu); iommu_enable_ga(iommu); + iommu_enable_xt(iommu); iommu_enable(iommu); iommu_flush_all_caches(iommu); } @@ -2212,6 +2233,7 @@ static void early_enable_iommus(void) iommu_enable_command_buffer(iommu); iommu_enable_event_buffer(iommu); iommu_enable_ga(iommu); + iommu_enable_xt(iommu); iommu_set_device_table(iommu); iommu_flush_all_caches(iommu); } @@ -2691,8 +2713,7 @@ int __init amd_iommu_enable(void) return ret; irq_remapping_enabled = 1; - - return 0; + return amd_iommu_xt_mode; } void amd_iommu_disable(void) @@ -2721,6 +2742,7 @@ int __init amd_iommu_enable_faulting(void) */ static int __init amd_iommu_init(void) { + struct amd_iommu *iommu; int ret; ret = iommu_go_to_state(IOMMU_INITIALIZED); @@ -2730,14 +2752,15 @@ static int __init amd_iommu_init(void) disable_iommus(); free_iommu_resources(); } else { - struct amd_iommu *iommu; - uninit_device_table_dma(); for_each_iommu(iommu) iommu_flush_all_caches(iommu); } } + for_each_iommu(iommu) + amd_iommu_debugfs_setup(iommu); + return ret; } diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h index 640c286a0ab9..a8cd0296fb16 100644 --- a/drivers/iommu/amd_iommu_proto.h +++ b/drivers/iommu/amd_iommu_proto.h @@ -33,6 +33,12 @@ extern void amd_iommu_uninit_devices(void); extern void amd_iommu_init_notifier(void); extern int amd_iommu_init_api(void); +#ifdef CONFIG_AMD_IOMMU_DEBUGFS +void amd_iommu_debugfs_setup(struct amd_iommu *iommu); +#else +static inline void amd_iommu_debugfs_setup(struct amd_iommu *iommu) {} +#endif + /* Needed for interrupt remapping */ extern int amd_iommu_prepare(void); extern int amd_iommu_enable(void); diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 986cbe0cc189..e2b342e65a7b 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -161,6 +161,7 @@ #define CONTROL_GAM_EN 0x19ULL #define CONTROL_GALOG_EN 0x1CULL #define CONTROL_GAINT_EN 0x1DULL +#define CONTROL_XT_EN 0x32ULL #define CTRL_INV_TO_MASK (7 << CONTROL_INV_TIMEOUT) #define CTRL_INV_TO_NONE 0 @@ -378,9 +379,11 @@ #define IOMMU_CAP_EFR 27 /* IOMMU Feature Reporting Field (for IVHD type 10h */ +#define IOMMU_FEAT_XTSUP_SHIFT 0 #define IOMMU_FEAT_GASUP_SHIFT 6 /* IOMMU Extended Feature Register (EFR) */ +#define IOMMU_EFR_XTSUP_SHIFT 2 #define IOMMU_EFR_GASUP_SHIFT 7 #define MAX_DOMAIN_ID 65536 @@ -437,7 +440,6 @@ extern struct kmem_cache *amd_iommu_irq_cache; #define APERTURE_RANGE_INDEX(a) ((a) >> APERTURE_RANGE_SHIFT) #define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL) - /* * This struct is used to pass information about * incoming PPR faults around. @@ -594,6 +596,11 @@ struct amd_iommu { u32 flags; volatile u64 __aligned(8) cmd_sem; + +#ifdef CONFIG_AMD_IOMMU_DEBUGFS + /* DebugFS Info */ + struct dentry *debugfs; +#endif }; static inline struct amd_iommu *dev_to_amd_iommu(struct device *dev) @@ -810,6 +817,9 @@ union irte { } fields; }; +#define APICID_TO_IRTE_DEST_LO(x) (x & 0xffffff) +#define APICID_TO_IRTE_DEST_HI(x) ((x >> 24) & 0xff) + union irte_ga_lo { u64 val; @@ -823,8 +833,8 @@ union irte_ga_lo { dm : 1, /* ------ */ guest_mode : 1, - destination : 8, - rsvd : 48; + destination : 24, + ga_tag : 32; } fields_remap; /* For guest vAPIC */ @@ -837,8 +847,7 @@ union irte_ga_lo { is_run : 1, /* ------ */ guest_mode : 1, - destination : 8, - rsvd2 : 16, + destination : 24, ga_tag : 32; } fields_vapic; }; @@ -849,7 +858,8 @@ union irte_ga_hi { u64 vector : 8, rsvd_1 : 4, ga_root_ptr : 40, - rsvd_2 : 12; + rsvd_2 : 4, + destination : 8; } fields; }; diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 22bdabd3d8e0..5059d09f3202 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -24,6 +24,7 @@ #include <linux/acpi_iort.h> #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/crash_dump.h> #include <linux/delay.h> #include <linux/dma-iommu.h> #include <linux/err.h> @@ -366,7 +367,7 @@ #define MSI_IOVA_BASE 0x8000000 #define MSI_IOVA_LENGTH 0x100000 -static bool disable_bypass; +static bool disable_bypass = 1; module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO); MODULE_PARM_DESC(disable_bypass, "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU."); @@ -1301,6 +1302,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev) /* Sync our overflow flag, as we believe we're up to speed */ q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons); + writel(q->cons, q->cons_reg); return IRQ_HANDLED; } @@ -1997,7 +1999,6 @@ static struct iommu_ops arm_smmu_ops = { .attach_dev = arm_smmu_attach_dev, .map = arm_smmu_map, .unmap = arm_smmu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = arm_smmu_iotlb_sync, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, @@ -2211,8 +2212,12 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr) reg &= ~clr; reg |= set; writel_relaxed(reg | GBPA_UPDATE, gbpa); - return readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE), - 1, ARM_SMMU_POLL_TIMEOUT_US); + ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE), + 1, ARM_SMMU_POLL_TIMEOUT_US); + + if (ret) + dev_err(smmu->dev, "GBPA not responding to update\n"); + return ret; } static void arm_smmu_free_msis(void *data) @@ -2392,8 +2397,15 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) /* Clear CR0 and sync (disables SMMU and queue processing) */ reg = readl_relaxed(smmu->base + ARM_SMMU_CR0); - if (reg & CR0_SMMUEN) + if (reg & CR0_SMMUEN) { + if (is_kdump_kernel()) { + arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0); + arm_smmu_device_disable(smmu); + return -EBUSY; + } + dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n"); + } ret = arm_smmu_device_disable(smmu); if (ret) @@ -2491,10 +2503,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) enables |= CR0_SMMUEN; } else { ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT); - if (ret) { - dev_err(smmu->dev, "GBPA not responding to update\n"); + if (ret) return ret; - } } ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, ARM_SMMU_CR0ACK); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index c73cfce1ccc0..fd1b80ef9490 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1562,7 +1562,6 @@ static struct iommu_ops arm_smmu_ops = { .attach_dev = arm_smmu_attach_dev, .map = arm_smmu_map, .unmap = arm_smmu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = arm_smmu_iotlb_sync, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, @@ -2103,12 +2102,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev) if (err) return err; - if (smmu->version == ARM_SMMU_V2 && - smmu->num_context_banks != smmu->num_context_irqs) { - dev_err(dev, - "found only %d context interrupt(s) but %d required\n", - smmu->num_context_irqs, smmu->num_context_banks); - return -ENODEV; + if (smmu->version == ARM_SMMU_V2) { + if (smmu->num_context_banks > smmu->num_context_irqs) { + dev_err(dev, + "found only %d context irq(s) but %d required\n", + smmu->num_context_irqs, smmu->num_context_banks); + return -ENODEV; + } + + /* Ignore superfluous interrupts */ + smmu->num_context_irqs = smmu->num_context_banks; } for (i = 0; i < smmu->num_global_irqs; ++i) { diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 75456b5aa825..d9c748b6f9e4 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1339,8 +1339,8 @@ void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, qi_submit_sync(&desc, iommu); } -void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, - u64 addr, unsigned mask) +void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid, + u16 qdep, u64 addr, unsigned mask) { struct qi_desc desc; @@ -1355,7 +1355,7 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, qdep = 0; desc.low = QI_DEV_IOTLB_SID(sid) | QI_DEV_IOTLB_QDEP(qdep) | - QI_DIOTLB_TYPE; + QI_DIOTLB_TYPE | QI_DEV_IOTLB_PFSID(pfsid); qi_submit_sync(&desc, iommu); } diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index b128cb4372d3..1bd0cd7168df 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1332,7 +1332,6 @@ static const struct iommu_ops exynos_iommu_ops = { .detach_dev = exynos_iommu_detach_device, .map = exynos_iommu_map, .unmap = exynos_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = exynos_iommu_iova_to_phys, .device_group = generic_device_group, .add_device = exynos_iommu_add_device, diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 6a237d18fabf..5f3f10cf9d9d 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -52,6 +52,7 @@ #include <asm/iommu.h> #include "irq_remapping.h" +#include "intel-pasid.h" #define ROOT_SIZE VTD_PAGE_SIZE #define CONTEXT_SIZE VTD_PAGE_SIZE @@ -379,60 +380,6 @@ static int hw_pass_through = 1; for (idx = 0; idx < g_num_of_iommus; idx++) \ if (domain->iommu_refcnt[idx]) -struct dmar_domain { - int nid; /* node id */ - - unsigned iommu_refcnt[DMAR_UNITS_SUPPORTED]; - /* Refcount of devices per iommu */ - - - u16 iommu_did[DMAR_UNITS_SUPPORTED]; - /* Domain ids per IOMMU. Use u16 since - * domain ids are 16 bit wide according - * to VT-d spec, section 9.3 */ - - bool has_iotlb_device; - struct list_head devices; /* all devices' list */ - struct iova_domain iovad; /* iova's that belong to this domain */ - - struct dma_pte *pgd; /* virtual address */ - int gaw; /* max guest address width */ - - /* adjusted guest address width, 0 is level 2 30-bit */ - int agaw; - - int flags; /* flags to find out type of domain */ - - int iommu_coherency;/* indicate coherency of iommu access */ - int iommu_snooping; /* indicate snooping control feature*/ - int iommu_count; /* reference count of iommu */ - int iommu_superpage;/* Level of superpages supported: - 0 == 4KiB (no superpages), 1 == 2MiB, - 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */ - u64 max_addr; /* maximum mapped address */ - - struct iommu_domain domain; /* generic domain data structure for - iommu core */ -}; - -/* PCI domain-device relationship */ -struct device_domain_info { - struct list_head link; /* link to domain siblings */ - struct list_head global; /* link to global list */ - u8 bus; /* PCI bus number */ - u8 devfn; /* PCI devfn number */ - u8 pasid_supported:3; - u8 pasid_enabled:1; - u8 pri_supported:1; - u8 pri_enabled:1; - u8 ats_supported:1; - u8 ats_enabled:1; - u8 ats_qdep; - struct device *dev; /* it's NULL for PCIe-to-PCI bridge */ - struct intel_iommu *iommu; /* IOMMU used by this device */ - struct dmar_domain *domain; /* pointer to domain */ -}; - struct dmar_rmrr_unit { struct list_head list; /* list of rmrr units */ struct acpi_dmar_header *hdr; /* ACPI header */ @@ -523,6 +470,27 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped); static DEFINE_SPINLOCK(device_domain_lock); static LIST_HEAD(device_domain_list); +/* + * Iterate over elements in device_domain_list and call the specified + * callback @fn against each element. This helper should only be used + * in the context where the device_domain_lock has already been holden. + */ +int for_each_device_domain(int (*fn)(struct device_domain_info *info, + void *data), void *data) +{ + int ret = 0; + struct device_domain_info *info; + + assert_spin_locked(&device_domain_lock); + list_for_each_entry(info, &device_domain_list, global) { + ret = fn(info, data); + if (ret) + return ret; + } + + return 0; +} + const struct iommu_ops intel_iommu_ops; static bool translation_pre_enabled(struct intel_iommu *iommu) @@ -629,7 +597,7 @@ static void set_iommu_domain(struct intel_iommu *iommu, u16 did, domains[did & 0xff] = domain; } -static inline void *alloc_pgtable_page(int node) +void *alloc_pgtable_page(int node) { struct page *page; void *vaddr = NULL; @@ -640,7 +608,7 @@ static inline void *alloc_pgtable_page(int node) return vaddr; } -static inline void free_pgtable_page(void *vaddr) +void free_pgtable_page(void *vaddr) { free_page((unsigned long)vaddr); } @@ -723,7 +691,7 @@ int iommu_calculate_agaw(struct intel_iommu *iommu) } /* This functionin only returns single iommu in a domain */ -static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) +struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) { int iommu_id; @@ -1501,6 +1469,20 @@ static void iommu_enable_dev_iotlb(struct device_domain_info *info) return; pdev = to_pci_dev(info->dev); + /* For IOMMU that supports device IOTLB throttling (DIT), we assign + * PFSID to the invalidation desc of a VF such that IOMMU HW can gauge + * queue depth at PF level. If DIT is not set, PFSID will be treated as + * reserved, which should be set to 0. + */ + if (!ecap_dit(info->iommu->ecap)) + info->pfsid = 0; + else { + struct pci_dev *pf_pdev; + + /* pdev will be returned if device is not a vf */ + pf_pdev = pci_physfn(pdev); + info->pfsid = PCI_DEVID(pf_pdev->bus->number, pf_pdev->devfn); + } #ifdef CONFIG_INTEL_IOMMU_SVM /* The PCIe spec, in its wisdom, declares that the behaviour of @@ -1566,7 +1548,8 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, sid = info->bus << 8 | info->devfn; qdep = info->ats_qdep; - qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask); + qi_flush_dev_iotlb(info->iommu, sid, info->pfsid, + qdep, addr, mask); } spin_unlock_irqrestore(&device_domain_lock, flags); } @@ -1800,7 +1783,7 @@ static void free_dmar_iommu(struct intel_iommu *iommu) if (pasid_enabled(iommu)) { if (ecap_prs(iommu->ecap)) intel_svm_finish_prq(iommu); - intel_svm_free_pasid_tables(iommu); + intel_svm_exit(iommu); } #endif } @@ -2495,6 +2478,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, info->dev = dev; info->domain = domain; info->iommu = iommu; + info->pasid_table = NULL; if (dev && dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(info->dev); @@ -2552,6 +2536,15 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, list_add(&info->global, &device_domain_list); if (dev) dev->archdata.iommu = info; + + if (dev && dev_is_pci(dev) && info->pasid_supported) { + ret = intel_pasid_alloc_table(dev); + if (ret) { + __dmar_remove_one_dev_info(info); + spin_unlock_irqrestore(&device_domain_lock, flags); + return NULL; + } + } spin_unlock_irqrestore(&device_domain_lock, flags); if (dev && domain_context_mapping(domain, dev)) { @@ -3304,6 +3297,18 @@ static int __init init_dmars(void) } for_each_active_iommu(iommu, drhd) { + /* + * Find the max pasid size of all IOMMU's in the system. + * We need to ensure the system pasid table is no bigger + * than the smallest supported. + */ + if (pasid_enabled(iommu)) { + u32 temp = 2 << ecap_pss(iommu->ecap); + + intel_pasid_max_id = min_t(u32, temp, + intel_pasid_max_id); + } + g_iommus[iommu->seq_id] = iommu; intel_iommu_init_qi(iommu); @@ -3359,7 +3364,7 @@ static int __init init_dmars(void) hw_pass_through = 0; #ifdef CONFIG_INTEL_IOMMU_SVM if (pasid_enabled(iommu)) - intel_svm_alloc_pasid_tables(iommu); + intel_svm_init(iommu); #endif } @@ -3526,7 +3531,7 @@ static unsigned long intel_alloc_iova(struct device *dev, return iova_pfn; } -static struct dmar_domain *get_valid_domain_for_dev(struct device *dev) +struct dmar_domain *get_valid_domain_for_dev(struct device *dev) { struct dmar_domain *domain, *tmp; struct dmar_rmrr_unit *rmrr; @@ -4354,7 +4359,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru) #ifdef CONFIG_INTEL_IOMMU_SVM if (pasid_enabled(iommu)) - intel_svm_alloc_pasid_tables(iommu); + intel_svm_init(iommu); #endif if (dmaru->ignored) { @@ -4906,6 +4911,7 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info) if (info->dev) { iommu_disable_dev_iotlb(info); domain_context_clear(iommu, info->dev); + intel_pasid_free_table(info->dev); } unlink_domain_info(info); @@ -5231,22 +5237,16 @@ static void intel_iommu_put_resv_regions(struct device *dev, #ifdef CONFIG_INTEL_IOMMU_SVM #define MAX_NR_PASID_BITS (20) -static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) +static inline unsigned long intel_iommu_get_pts(struct device *dev) { - /* - * Convert ecap_pss to extend context entry pts encoding, also - * respect the soft pasid_max value set by the iommu. - * - number of PASID bits = ecap_pss + 1 - * - number of PASID table entries = 2^(pts + 5) - * Therefore, pts = ecap_pss - 4 - * e.g. KBL ecap_pss = 0x13, PASID has 20 bits, pts = 15 - */ - if (ecap_pss(iommu->ecap) < 5) + int pts, max_pasid; + + max_pasid = intel_pasid_get_dev_max_id(dev); + pts = find_first_bit((unsigned long *)&max_pasid, MAX_NR_PASID_BITS); + if (pts < 5) return 0; - /* pasid_max is encoded as actual number of entries not the bits */ - return find_first_bit((unsigned long *)&iommu->pasid_max, - MAX_NR_PASID_BITS) - 5; + return pts - 5; } int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) @@ -5282,8 +5282,8 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd if (!(ctx_lo & CONTEXT_PASIDE)) { if (iommu->pasid_state_table) context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); - context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | - intel_iommu_get_pts(iommu); + context[1].lo = (u64)virt_to_phys(info->pasid_table->table) | + intel_iommu_get_pts(sdev->dev); wmb(); /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both @@ -5350,11 +5350,6 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev) return NULL; } - if (!iommu->pasid_table) { - dev_err(dev, "PASID not enabled on IOMMU; cannot enable SVM\n"); - return NULL; - } - return iommu; } #endif /* CONFIG_INTEL_IOMMU_SVM */ @@ -5367,7 +5362,6 @@ const struct iommu_ops intel_iommu_ops = { .detach_dev = intel_iommu_detach_device, .map = intel_iommu_map, .unmap = intel_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = intel_iommu_iova_to_phys, .add_device = intel_iommu_add_device, .remove_device = intel_iommu_remove_device, diff --git a/drivers/iommu/intel-pasid.c b/drivers/iommu/intel-pasid.c new file mode 100644 index 000000000000..fe95c9bd4d33 --- /dev/null +++ b/drivers/iommu/intel-pasid.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * intel-pasid.c - PASID idr, table and entry manipulation + * + * Copyright (C) 2018 Intel Corporation + * + * Author: Lu Baolu <baolu.lu@linux.intel.com> + */ + +#define pr_fmt(fmt) "DMAR: " fmt + +#include <linux/dmar.h> +#include <linux/intel-iommu.h> +#include <linux/iommu.h> +#include <linux/memory.h> +#include <linux/pci.h> +#include <linux/pci-ats.h> +#include <linux/spinlock.h> + +#include "intel-pasid.h" + +/* + * Intel IOMMU system wide PASID name space: + */ +static DEFINE_SPINLOCK(pasid_lock); +u32 intel_pasid_max_id = PASID_MAX; +static DEFINE_IDR(pasid_idr); + +int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp) +{ + int ret, min, max; + + min = max_t(int, start, PASID_MIN); + max = min_t(int, end, intel_pasid_max_id); + + WARN_ON(in_interrupt()); + idr_preload(gfp); + spin_lock(&pasid_lock); + ret = idr_alloc(&pasid_idr, ptr, min, max, GFP_ATOMIC); + spin_unlock(&pasid_lock); + idr_preload_end(); + + return ret; +} + +void intel_pasid_free_id(int pasid) +{ + spin_lock(&pasid_lock); + idr_remove(&pasid_idr, pasid); + spin_unlock(&pasid_lock); +} + +void *intel_pasid_lookup_id(int pasid) +{ + void *p; + + spin_lock(&pasid_lock); + p = idr_find(&pasid_idr, pasid); + spin_unlock(&pasid_lock); + + return p; +} + +/* + * Per device pasid table management: + */ +static inline void +device_attach_pasid_table(struct device_domain_info *info, + struct pasid_table *pasid_table) +{ + info->pasid_table = pasid_table; + list_add(&info->table, &pasid_table->dev); +} + +static inline void +device_detach_pasid_table(struct device_domain_info *info, + struct pasid_table *pasid_table) +{ + info->pasid_table = NULL; + list_del(&info->table); +} + +struct pasid_table_opaque { + struct pasid_table **pasid_table; + int segment; + int bus; + int devfn; +}; + +static int search_pasid_table(struct device_domain_info *info, void *opaque) +{ + struct pasid_table_opaque *data = opaque; + + if (info->iommu->segment == data->segment && + info->bus == data->bus && + info->devfn == data->devfn && + info->pasid_table) { + *data->pasid_table = info->pasid_table; + return 1; + } + + return 0; +} + +static int get_alias_pasid_table(struct pci_dev *pdev, u16 alias, void *opaque) +{ + struct pasid_table_opaque *data = opaque; + + data->segment = pci_domain_nr(pdev->bus); + data->bus = PCI_BUS_NUM(alias); + data->devfn = alias & 0xff; + + return for_each_device_domain(&search_pasid_table, data); +} + +/* + * Allocate a pasid table for @dev. It should be called in a + * single-thread context. + */ +int intel_pasid_alloc_table(struct device *dev) +{ + struct device_domain_info *info; + struct pasid_table *pasid_table; + struct pasid_table_opaque data; + struct page *pages; + size_t size, count; + int ret, order; + + info = dev->archdata.iommu; + if (WARN_ON(!info || !dev_is_pci(dev) || + !info->pasid_supported || info->pasid_table)) + return -EINVAL; + + /* DMA alias device already has a pasid table, use it: */ + data.pasid_table = &pasid_table; + ret = pci_for_each_dma_alias(to_pci_dev(dev), + &get_alias_pasid_table, &data); + if (ret) + goto attach_out; + + pasid_table = kzalloc(sizeof(*pasid_table), GFP_ATOMIC); + if (!pasid_table) + return -ENOMEM; + INIT_LIST_HEAD(&pasid_table->dev); + + size = sizeof(struct pasid_entry); + count = min_t(int, pci_max_pasids(to_pci_dev(dev)), intel_pasid_max_id); + order = get_order(size * count); + pages = alloc_pages_node(info->iommu->node, + GFP_ATOMIC | __GFP_ZERO, + order); + if (!pages) + return -ENOMEM; + + pasid_table->table = page_address(pages); + pasid_table->order = order; + pasid_table->max_pasid = count; + +attach_out: + device_attach_pasid_table(info, pasid_table); + + return 0; +} + +void intel_pasid_free_table(struct device *dev) +{ + struct device_domain_info *info; + struct pasid_table *pasid_table; + + info = dev->archdata.iommu; + if (!info || !dev_is_pci(dev) || + !info->pasid_supported || !info->pasid_table) + return; + + pasid_table = info->pasid_table; + device_detach_pasid_table(info, pasid_table); + + if (!list_empty(&pasid_table->dev)) + return; + + free_pages((unsigned long)pasid_table->table, pasid_table->order); + kfree(pasid_table); +} + +struct pasid_table *intel_pasid_get_table(struct device *dev) +{ + struct device_domain_info *info; + + info = dev->archdata.iommu; + if (!info) + return NULL; + + return info->pasid_table; +} + +int intel_pasid_get_dev_max_id(struct device *dev) +{ + struct device_domain_info *info; + + info = dev->archdata.iommu; + if (!info || !info->pasid_table) + return 0; + + return info->pasid_table->max_pasid; +} + +struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid) +{ + struct pasid_table *pasid_table; + struct pasid_entry *entries; + + pasid_table = intel_pasid_get_table(dev); + if (WARN_ON(!pasid_table || pasid < 0 || + pasid >= intel_pasid_get_dev_max_id(dev))) + return NULL; + + entries = pasid_table->table; + + return &entries[pasid]; +} + +/* + * Interfaces for PASID table entry manipulation: + */ +static inline void pasid_clear_entry(struct pasid_entry *pe) +{ + WRITE_ONCE(pe->val, 0); +} + +void intel_pasid_clear_entry(struct device *dev, int pasid) +{ + struct pasid_entry *pe; + + pe = intel_pasid_get_entry(dev, pasid); + if (WARN_ON(!pe)) + return; + + pasid_clear_entry(pe); +} diff --git a/drivers/iommu/intel-pasid.h b/drivers/iommu/intel-pasid.h new file mode 100644 index 000000000000..1c05ed6fc5a5 --- /dev/null +++ b/drivers/iommu/intel-pasid.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * intel-pasid.h - PASID idr, table and entry header + * + * Copyright (C) 2018 Intel Corporation + * + * Author: Lu Baolu <baolu.lu@linux.intel.com> + */ + +#ifndef __INTEL_PASID_H +#define __INTEL_PASID_H + +#define PASID_MIN 0x1 +#define PASID_MAX 0x100000 + +struct pasid_entry { + u64 val; +}; + +/* The representative of a PASID table */ +struct pasid_table { + void *table; /* pasid table pointer */ + int order; /* page order of pasid table */ + int max_pasid; /* max pasid */ + struct list_head dev; /* device list */ +}; + +extern u32 intel_pasid_max_id; +int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); +void intel_pasid_free_id(int pasid); +void *intel_pasid_lookup_id(int pasid); +int intel_pasid_alloc_table(struct device *dev); +void intel_pasid_free_table(struct device *dev); +struct pasid_table *intel_pasid_get_table(struct device *dev); +int intel_pasid_get_dev_max_id(struct device *dev); +struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid); +void intel_pasid_clear_entry(struct device *dev, int pasid); + +#endif /* __INTEL_PASID_H */ diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index 7d65aab36a96..4a03e5090952 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -27,21 +27,19 @@ #include <linux/mm_types.h> #include <asm/page.h> +#include "intel-pasid.h" + #define PASID_ENTRY_P BIT_ULL(0) #define PASID_ENTRY_FLPM_5LP BIT_ULL(9) #define PASID_ENTRY_SRE BIT_ULL(11) static irqreturn_t prq_event_thread(int irq, void *d); -struct pasid_entry { - u64 val; -}; - struct pasid_state_entry { u64 val; }; -int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu) +int intel_svm_init(struct intel_iommu *iommu) { struct page *pages; int order; @@ -66,15 +64,6 @@ int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu) iommu->pasid_max = 0x20000; order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max); - pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); - if (!pages) { - pr_warn("IOMMU: %s: Failed to allocate PASID table\n", - iommu->name); - return -ENOMEM; - } - iommu->pasid_table = page_address(pages); - pr_info("%s: Allocated order %d PASID table.\n", iommu->name, order); - if (ecap_dis(iommu->ecap)) { /* Just making it explicit... */ BUILD_BUG_ON(sizeof(struct pasid_entry) != sizeof(struct pasid_state_entry)); @@ -86,24 +75,18 @@ int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu) iommu->name); } - idr_init(&iommu->pasid_idr); - return 0; } -int intel_svm_free_pasid_tables(struct intel_iommu *iommu) +int intel_svm_exit(struct intel_iommu *iommu) { int order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max); - if (iommu->pasid_table) { - free_pages((unsigned long)iommu->pasid_table, order); - iommu->pasid_table = NULL; - } if (iommu->pasid_state_table) { free_pages((unsigned long)iommu->pasid_state_table, order); iommu->pasid_state_table = NULL; } - idr_destroy(&iommu->pasid_idr); + return 0; } @@ -279,11 +262,9 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) * page) so that we end up taking a fault that the hardware really * *has* to handle gracefully without affecting other processes. */ - svm->iommu->pasid_table[svm->pasid].val = 0; - wmb(); - rcu_read_lock(); list_for_each_entry_rcu(sdev, &svm->devs, list) { + intel_pasid_clear_entry(sdev->dev, svm->pasid); intel_flush_pasid_dev(svm, sdev, svm->pasid); intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm); } @@ -299,10 +280,12 @@ static const struct mmu_notifier_ops intel_mmuops = { }; static DEFINE_MUTEX(pasid_mutex); +static LIST_HEAD(global_svm_list); int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ops *ops) { struct intel_iommu *iommu = intel_svm_device_to_iommu(dev); + struct pasid_entry *entry; struct intel_svm_dev *sdev; struct intel_svm *svm = NULL; struct mm_struct *mm = NULL; @@ -310,7 +293,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ int pasid_max; int ret; - if (WARN_ON(!iommu || !iommu->pasid_table)) + if (!iommu) return -EINVAL; if (dev_is_pci(dev)) { @@ -330,13 +313,13 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ mutex_lock(&pasid_mutex); if (pasid && !(flags & SVM_FLAG_PRIVATE_PASID)) { - int i; + struct intel_svm *t; - idr_for_each_entry(&iommu->pasid_idr, svm, i) { - if (svm->mm != mm || - (svm->flags & SVM_FLAG_PRIVATE_PASID)) + list_for_each_entry(t, &global_svm_list, list) { + if (t->mm != mm || (t->flags & SVM_FLAG_PRIVATE_PASID)) continue; + svm = t; if (svm->pasid >= pasid_max) { dev_warn(dev, "Limited PASID width. Cannot use existing PASID %d\n", @@ -388,13 +371,13 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ } svm->iommu = iommu; - if (pasid_max > iommu->pasid_max) - pasid_max = iommu->pasid_max; + if (pasid_max > intel_pasid_max_id) + pasid_max = intel_pasid_max_id; /* Do not use PASID 0 in caching mode (virtualised IOMMU) */ - ret = idr_alloc(&iommu->pasid_idr, svm, - !!cap_caching_mode(iommu->cap), - pasid_max - 1, GFP_KERNEL); + ret = intel_pasid_alloc_id(svm, + !!cap_caching_mode(iommu->cap), + pasid_max - 1, GFP_KERNEL); if (ret < 0) { kfree(svm); kfree(sdev); @@ -405,11 +388,12 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ svm->mm = mm; svm->flags = flags; INIT_LIST_HEAD_RCU(&svm->devs); + INIT_LIST_HEAD(&svm->list); ret = -ENOMEM; if (mm) { ret = mmu_notifier_register(&svm->notifier, mm); if (ret) { - idr_remove(&svm->iommu->pasid_idr, svm->pasid); + intel_pasid_free_id(svm->pasid); kfree(svm); kfree(sdev); goto out; @@ -421,7 +405,8 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ if (cpu_feature_enabled(X86_FEATURE_LA57)) pasid_entry_val |= PASID_ENTRY_FLPM_5LP; - iommu->pasid_table[svm->pasid].val = pasid_entry_val; + entry = intel_pasid_get_entry(dev, svm->pasid); + entry->val = pasid_entry_val; wmb(); @@ -431,6 +416,8 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ */ if (cap_caching_mode(iommu->cap)) intel_flush_pasid_dev(svm, sdev, svm->pasid); + + list_add_tail(&svm->list, &global_svm_list); } list_add_rcu(&sdev->list, &svm->devs); @@ -454,10 +441,10 @@ int intel_svm_unbind_mm(struct device *dev, int pasid) mutex_lock(&pasid_mutex); iommu = intel_svm_device_to_iommu(dev); - if (!iommu || !iommu->pasid_table) + if (!iommu) goto out; - svm = idr_find(&iommu->pasid_idr, pasid); + svm = intel_pasid_lookup_id(pasid); if (!svm) goto out; @@ -477,15 +464,15 @@ int intel_svm_unbind_mm(struct device *dev, int pasid) intel_flush_pasid_dev(svm, sdev, svm->pasid); intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm); kfree_rcu(sdev, rcu); + intel_pasid_clear_entry(dev, svm->pasid); if (list_empty(&svm->devs)) { - svm->iommu->pasid_table[svm->pasid].val = 0; - wmb(); - - idr_remove(&svm->iommu->pasid_idr, svm->pasid); + intel_pasid_free_id(svm->pasid); if (svm->mm) mmu_notifier_unregister(&svm->notifier, svm->mm); + list_del(&svm->list); + /* We mandate that no page faults may be outstanding * for the PASID when intel_svm_unbind_mm() is called. * If that is not obeyed, subtle errors will happen. @@ -512,10 +499,10 @@ int intel_svm_is_pasid_valid(struct device *dev, int pasid) mutex_lock(&pasid_mutex); iommu = intel_svm_device_to_iommu(dev); - if (!iommu || !iommu->pasid_table) + if (!iommu) goto out; - svm = idr_find(&iommu->pasid_idr, pasid); + svm = intel_pasid_lookup_id(pasid); if (!svm) goto out; @@ -614,7 +601,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) if (!svm || svm->pasid != req->pasid) { rcu_read_lock(); - svm = idr_find(&iommu->pasid_idr, req->pasid); + svm = intel_pasid_lookup_id(req->pasid); /* It *can't* go away, because the driver is not permitted * to unbind the mm while any page faults are outstanding. * So we only need RCU to protect the internal idr code. */ diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 50e3a9fcf43e..b5948ba6b3b3 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -192,6 +192,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, { struct io_pgtable_cfg *cfg = &data->iop.cfg; struct device *dev = cfg->iommu_dev; + phys_addr_t phys; dma_addr_t dma; size_t size = ARM_V7S_TABLE_SIZE(lvl); void *table = NULL; @@ -200,6 +201,10 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size)); else if (lvl == 2) table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA); + phys = virt_to_phys(table); + if (phys != (arm_v7s_iopte)phys) + /* Doesn't fit in PTE */ + goto out_free; if (table && !(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) { dma = dma_map_single(dev, table, size, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) @@ -209,7 +214,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, * address directly, so if the DMA layer suggests otherwise by * translating or truncating them, that bodes very badly... */ - if (dma != virt_to_phys(table)) + if (dma != phys) goto out_unmap; } kmemleak_ignore(table); diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 010a254305dd..88641b4560bc 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -237,7 +237,8 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp, void *pages; VM_BUG_ON((gfp & __GFP_HIGHMEM)); - p = alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, order); + p = alloc_pages_node(dev ? dev_to_node(dev) : NUMA_NO_NODE, + gfp | __GFP_ZERO, order); if (!p) return NULL; diff --git a/drivers/iommu/iommu-debugfs.c b/drivers/iommu/iommu-debugfs.c new file mode 100644 index 000000000000..3b1bf88fd1b0 --- /dev/null +++ b/drivers/iommu/iommu-debugfs.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IOMMU debugfs core infrastructure + * + * Copyright (C) 2018 Advanced Micro Devices, Inc. + * + * Author: Gary R Hook <gary.hook@amd.com> + */ + +#include <linux/pci.h> +#include <linux/iommu.h> +#include <linux/debugfs.h> + +struct dentry *iommu_debugfs_dir; + +/** + * iommu_debugfs_setup - create the top-level iommu directory in debugfs + * + * Provide base enablement for using debugfs to expose internal data of an + * IOMMU driver. When called, this function creates the + * /sys/kernel/debug/iommu directory. + * + * Emit a strong warning at boot time to indicate that this feature is + * enabled. + * + * This function is called from iommu_init; drivers may then call + * iommu_debugfs_new_driver_dir() to instantiate a vendor-specific + * directory to be used to expose internal data. + */ +void iommu_debugfs_setup(void) +{ + if (!iommu_debugfs_dir) { + iommu_debugfs_dir = debugfs_create_dir("iommu", NULL); + pr_warn("\n"); + pr_warn("*************************************************************\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("** **\n"); + pr_warn("** IOMMU DebugFS SUPPORT HAS BEEN ENABLED IN THIS KERNEL **\n"); + pr_warn("** **\n"); + pr_warn("** This means that this kernel is built to expose internal **\n"); + pr_warn("** IOMMU data structures, which may compromise security on **\n"); + pr_warn("** your system. **\n"); + pr_warn("** **\n"); + pr_warn("** If you see this message and you are not debugging the **\n"); + pr_warn("** kernel, report this immediately to your vendor! **\n"); + pr_warn("** **\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("*************************************************************\n"); + } +} + +/** + * iommu_debugfs_new_driver_dir - create a vendor directory under debugfs/iommu + * @vendor: name of the vendor-specific subdirectory to create + * + * This function is called by an IOMMU driver to create the top-level debugfs + * directory for that driver. + * + * Return: upon success, a pointer to the dentry for the new directory. + * NULL in case of failure. + */ +struct dentry *iommu_debugfs_new_driver_dir(const char *vendor) +{ + return debugfs_create_dir(vendor, iommu_debugfs_dir); +} +EXPORT_SYMBOL_GPL(iommu_debugfs_new_driver_dir); diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 63b37563db7e..8c15c5980299 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -36,7 +36,11 @@ static struct kset *iommu_group_kset; static DEFINE_IDA(iommu_group_ida); +#ifdef CONFIG_IOMMU_DEFAULT_PASSTHROUGH +static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY; +#else static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA; +#endif struct iommu_callback_data { const struct iommu_ops *ops; @@ -294,11 +298,39 @@ static ssize_t iommu_group_show_resv_regions(struct iommu_group *group, return (str - buf); } +static ssize_t iommu_group_show_type(struct iommu_group *group, + char *buf) +{ + char *type = "unknown\n"; + + if (group->default_domain) { + switch (group->default_domain->type) { + case IOMMU_DOMAIN_BLOCKED: + type = "blocked\n"; + break; + case IOMMU_DOMAIN_IDENTITY: + type = "identity\n"; + break; + case IOMMU_DOMAIN_UNMANAGED: + type = "unmanaged\n"; + break; + case IOMMU_DOMAIN_DMA: + type = "DMA"; + break; + } + } + strcpy(buf, type); + + return strlen(type); +} + static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL); static IOMMU_GROUP_ATTR(reserved_regions, 0444, iommu_group_show_resv_regions, NULL); +static IOMMU_GROUP_ATTR(type, 0444, iommu_group_show_type, NULL); + static void iommu_group_release(struct kobject *kobj) { struct iommu_group *group = to_iommu_group(kobj); @@ -380,6 +412,10 @@ struct iommu_group *iommu_group_alloc(void) if (ret) return ERR_PTR(ret); + ret = iommu_group_create_file(group, &iommu_group_attr_type); + if (ret) + return ERR_PTR(ret); + pr_debug("Allocated group %d\n", group->id); return group; @@ -1637,8 +1673,8 @@ size_t iommu_unmap_fast(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_unmap_fast); -size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova, - struct scatterlist *sg, unsigned int nents, int prot) +size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, + struct scatterlist *sg, unsigned int nents, int prot) { struct scatterlist *s; size_t mapped = 0; @@ -1678,7 +1714,7 @@ out_err: return 0; } -EXPORT_SYMBOL_GPL(default_iommu_map_sg); +EXPORT_SYMBOL_GPL(iommu_map_sg); int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr, phys_addr_t paddr, u64 size, int prot) @@ -1748,6 +1784,8 @@ static int __init iommu_init(void) NULL, kernel_kobj); BUG_ON(!iommu_group_kset); + iommu_debugfs_setup(); + return 0; } core_initcall(iommu_init); diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index f026aa16d5f1..22b94f8a9a04 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -47,6 +47,7 @@ struct ipmmu_features { unsigned int number_of_contexts; bool setup_imbuscr; bool twobit_imttbcr_sl0; + bool reserved_context; }; struct ipmmu_vmsa_device { @@ -73,7 +74,7 @@ struct ipmmu_vmsa_domain { struct io_pgtable_ops *iop; unsigned int context_id; - spinlock_t lock; /* Protects mappings */ + struct mutex mutex; /* Protects mappings */ }; static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom) @@ -194,7 +195,9 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev) #define IMPMBA(n) (0x0280 + ((n) * 4)) #define IMPMBD(n) (0x02c0 + ((n) * 4)) -#define IMUCTR(n) (0x0300 + ((n) * 16)) +#define IMUCTR(n) ((n) < 32 ? IMUCTR0(n) : IMUCTR32(n)) +#define IMUCTR0(n) (0x0300 + ((n) * 16)) +#define IMUCTR32(n) (0x0600 + (((n) - 32) * 16)) #define IMUCTR_FIXADDEN (1 << 31) #define IMUCTR_FIXADD_MASK (0xff << 16) #define IMUCTR_FIXADD_SHIFT 16 @@ -204,7 +207,9 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev) #define IMUCTR_FLUSH (1 << 1) #define IMUCTR_MMUEN (1 << 0) -#define IMUASID(n) (0x0308 + ((n) * 16)) +#define IMUASID(n) ((n) < 32 ? IMUASID0(n) : IMUASID32(n)) +#define IMUASID0(n) (0x0308 + ((n) * 16)) +#define IMUASID32(n) (0x0608 + (((n) - 32) * 16)) #define IMUASID_ASID8_MASK (0xff << 8) #define IMUASID_ASID8_SHIFT 8 #define IMUASID_ASID0_MASK (0xff << 0) @@ -595,7 +600,7 @@ static struct iommu_domain *__ipmmu_domain_alloc(unsigned type) if (!domain) return NULL; - spin_lock_init(&domain->lock); + mutex_init(&domain->mutex); return &domain->io_domain; } @@ -641,7 +646,6 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct ipmmu_vmsa_device *mmu = to_ipmmu(dev); struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); - unsigned long flags; unsigned int i; int ret = 0; @@ -650,7 +654,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, return -ENXIO; } - spin_lock_irqsave(&domain->lock, flags); + mutex_lock(&domain->mutex); if (!domain->mmu) { /* The domain hasn't been used yet, initialize it. */ @@ -674,7 +678,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, } else dev_info(dev, "Reusing IPMMU context %u\n", domain->context_id); - spin_unlock_irqrestore(&domain->lock, flags); + mutex_unlock(&domain->mutex); if (ret < 0) return ret; @@ -756,8 +760,12 @@ static bool ipmmu_slave_whitelist(struct device *dev) return false; } -static const struct soc_device_attribute soc_r8a7795[] = { +static const struct soc_device_attribute soc_rcar_gen3[] = { { .soc_id = "r8a7795", }, + { .soc_id = "r8a7796", }, + { .soc_id = "r8a77965", }, + { .soc_id = "r8a77970", }, + { .soc_id = "r8a77995", }, { /* sentinel */ } }; @@ -765,7 +773,7 @@ static int ipmmu_of_xlate(struct device *dev, struct of_phandle_args *spec) { /* For R-Car Gen3 use a white list to opt-in slave devices */ - if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) + if (soc_device_match(soc_rcar_gen3) && !ipmmu_slave_whitelist(dev)) return -ENODEV; iommu_fwspec_add_ids(dev, spec->args, 1); @@ -889,7 +897,6 @@ static const struct iommu_ops ipmmu_ops = { .unmap = ipmmu_unmap, .flush_iotlb_all = ipmmu_iotlb_sync, .iotlb_sync = ipmmu_iotlb_sync, - .map_sg = default_iommu_map_sg, .iova_to_phys = ipmmu_iova_to_phys, .add_device = ipmmu_add_device, .remove_device = ipmmu_remove_device, @@ -917,14 +924,16 @@ static const struct ipmmu_features ipmmu_features_default = { .number_of_contexts = 1, /* software only tested with one context */ .setup_imbuscr = true, .twobit_imttbcr_sl0 = false, + .reserved_context = false, }; -static const struct ipmmu_features ipmmu_features_r8a7795 = { +static const struct ipmmu_features ipmmu_features_rcar_gen3 = { .use_ns_alias_offset = false, .has_cache_leaf_nodes = true, .number_of_contexts = 8, .setup_imbuscr = false, .twobit_imttbcr_sl0 = true, + .reserved_context = true, }; static const struct of_device_id ipmmu_of_ids[] = { @@ -933,7 +942,19 @@ static const struct of_device_id ipmmu_of_ids[] = { .data = &ipmmu_features_default, }, { .compatible = "renesas,ipmmu-r8a7795", - .data = &ipmmu_features_r8a7795, + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a7796", + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a77965", + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a77970", + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a77995", + .data = &ipmmu_features_rcar_gen3, }, { /* Terminator */ }, @@ -955,7 +976,7 @@ static int ipmmu_probe(struct platform_device *pdev) } mmu->dev = &pdev->dev; - mmu->num_utlbs = 32; + mmu->num_utlbs = 48; spin_lock_init(&mmu->lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = of_device_get_match_data(&pdev->dev); @@ -1018,6 +1039,11 @@ static int ipmmu_probe(struct platform_device *pdev) } ipmmu_device_reset(mmu); + + if (mmu->features->reserved_context) { + dev_info(&pdev->dev, "IPMMU context 0 is reserved\n"); + set_bit(0, mmu->ctx); + } } /* @@ -1081,12 +1107,19 @@ static struct platform_driver ipmmu_driver = { static int __init ipmmu_init(void) { + struct device_node *np; static bool setup_done; int ret; if (setup_done) return 0; + np = of_find_matching_node(NULL, ipmmu_of_ids); + if (!np) + return 0; + + of_node_put(np); + ret = platform_driver_register(&ipmmu_driver); if (ret < 0) return ret; diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 27377742600d..fc5f0b53adaf 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -395,20 +395,15 @@ static int msm_iommu_add_device(struct device *dev) struct msm_iommu_dev *iommu; struct iommu_group *group; unsigned long flags; - int ret = 0; spin_lock_irqsave(&msm_iommu_lock, flags); - iommu = find_iommu_for_dev(dev); + spin_unlock_irqrestore(&msm_iommu_lock, flags); + if (iommu) iommu_device_link(&iommu->iommu, dev); else - ret = -ENODEV; - - spin_unlock_irqrestore(&msm_iommu_lock, flags); - - if (ret) - return ret; + return -ENODEV; group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) @@ -425,13 +420,12 @@ static void msm_iommu_remove_device(struct device *dev) unsigned long flags; spin_lock_irqsave(&msm_iommu_lock, flags); - iommu = find_iommu_for_dev(dev); + spin_unlock_irqrestore(&msm_iommu_lock, flags); + if (iommu) iommu_device_unlink(&iommu->iommu, dev); - spin_unlock_irqrestore(&msm_iommu_lock, flags); - iommu_group_remove_device(dev); } @@ -708,7 +702,6 @@ static struct iommu_ops msm_iommu_ops = { .detach_dev = msm_iommu_detach_dev, .map = msm_iommu_map, .unmap = msm_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = msm_iommu_iova_to_phys, .add_device = msm_iommu_add_device, .remove_device = msm_iommu_remove_device, diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index f2832a10fcea..f9f69f7111a9 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -495,7 +495,6 @@ static struct iommu_ops mtk_iommu_ops = { .detach_dev = mtk_iommu_detach_device, .map = mtk_iommu_map, .unmap = mtk_iommu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = mtk_iommu_iotlb_sync, .iotlb_sync = mtk_iommu_iotlb_sync, .iova_to_phys = mtk_iommu_iova_to_phys, diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index a7c2a973784f..676c029494e4 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -531,7 +531,6 @@ static struct iommu_ops mtk_iommu_ops = { .detach_dev = mtk_iommu_detach_device, .map = mtk_iommu_map, .unmap = mtk_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = mtk_iommu_iova_to_phys, .add_device = mtk_iommu_add_device, .remove_device = mtk_iommu_remove_device, diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index af4a8e7fcd27..d2fb347aa4ff 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -550,7 +550,7 @@ static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd, pte_ready: iopte = iopte_offset(iopgd, da); - *pt_dma = virt_to_phys(iopte); + *pt_dma = iopgd_page_paddr(iopgd); dev_vdbg(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n", __func__, da, iopgd, *iopgd, iopte, *iopte); @@ -738,7 +738,7 @@ static size_t iopgtable_clear_entry_core(struct omap_iommu *obj, u32 da) } bytes *= nent; memset(iopte, 0, nent * sizeof(*iopte)); - pt_dma = virt_to_phys(iopte); + pt_dma = iopgd_page_paddr(iopgd); flush_iopte_range(obj->dev, pt_dma, pt_offset, nent); /* @@ -1548,7 +1548,6 @@ static const struct iommu_ops omap_iommu_ops = { .detach_dev = omap_iommu_detach_dev, .map = omap_iommu_map, .unmap = omap_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = omap_iommu_iova_to_phys, .add_device = omap_iommu_add_device, .remove_device = omap_iommu_remove_device, diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c index b48aee82d14b..ee70e9921cf1 100644 --- a/drivers/iommu/qcom_iommu.c +++ b/drivers/iommu/qcom_iommu.c @@ -590,7 +590,6 @@ static const struct iommu_ops qcom_iommu_ops = { .detach_dev = qcom_iommu_detach_dev, .map = qcom_iommu_map, .unmap = qcom_iommu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = qcom_iommu_iotlb_sync, .iotlb_sync = qcom_iommu_iotlb_sync, .iova_to_phys = qcom_iommu_iova_to_phys, diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index de8d3bf91b23..258115b10fa9 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -521,10 +521,11 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) u32 int_status; dma_addr_t iova; irqreturn_t ret = IRQ_NONE; - int i; + int i, err; - if (WARN_ON(!pm_runtime_get_if_in_use(iommu->dev))) - return 0; + err = pm_runtime_get_if_in_use(iommu->dev); + if (WARN_ON_ONCE(err <= 0)) + return ret; if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks))) goto out; @@ -620,11 +621,15 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain, spin_lock_irqsave(&rk_domain->iommus_lock, flags); list_for_each(pos, &rk_domain->iommus) { struct rk_iommu *iommu; + int ret; iommu = list_entry(pos, struct rk_iommu, node); /* Only zap TLBs of IOMMUs that are powered on. */ - if (pm_runtime_get_if_in_use(iommu->dev)) { + ret = pm_runtime_get_if_in_use(iommu->dev); + if (WARN_ON_ONCE(ret < 0)) + continue; + if (ret) { WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); rk_iommu_zap_lines(iommu, iova, size); @@ -891,6 +896,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, struct rk_iommu *iommu; struct rk_iommu_domain *rk_domain = to_rk_domain(domain); unsigned long flags; + int ret; /* Allow 'virtual devices' (eg drm) to detach from domain */ iommu = rk_iommu_from_dev(dev); @@ -909,7 +915,9 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, list_del_init(&iommu->node); spin_unlock_irqrestore(&rk_domain->iommus_lock, flags); - if (pm_runtime_get_if_in_use(iommu->dev)) { + ret = pm_runtime_get_if_in_use(iommu->dev); + WARN_ON_ONCE(ret < 0); + if (ret > 0) { rk_iommu_disable(iommu); pm_runtime_put(iommu->dev); } @@ -946,7 +954,8 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, list_add_tail(&iommu->node, &rk_domain->iommus); spin_unlock_irqrestore(&rk_domain->iommus_lock, flags); - if (!pm_runtime_get_if_in_use(iommu->dev)) + ret = pm_runtime_get_if_in_use(iommu->dev); + if (!ret || WARN_ON_ONCE(ret < 0)) return 0; ret = rk_iommu_enable(iommu); @@ -1110,7 +1119,6 @@ static const struct iommu_ops rk_iommu_ops = { .detach_dev = rk_iommu_detach_device, .map = rk_iommu_map, .unmap = rk_iommu_unmap, - .map_sg = default_iommu_map_sg, .add_device = rk_iommu_add_device, .remove_device = rk_iommu_remove_device, .iova_to_phys = rk_iommu_iova_to_phys, @@ -1152,17 +1160,6 @@ static int rk_iommu_probe(struct platform_device *pdev) if (iommu->num_mmu == 0) return PTR_ERR(iommu->bases[0]); - i = 0; - while ((irq = platform_get_irq(pdev, i++)) != -ENXIO) { - if (irq < 0) - return irq; - - err = devm_request_irq(iommu->dev, irq, rk_iommu_irq, - IRQF_SHARED, dev_name(dev), iommu); - if (err) - return err; - } - iommu->reset_disabled = device_property_read_bool(dev, "rockchip,disable-mmu-reset"); @@ -1219,6 +1216,19 @@ static int rk_iommu_probe(struct platform_device *pdev) pm_runtime_enable(dev); + i = 0; + while ((irq = platform_get_irq(pdev, i++)) != -ENXIO) { + if (irq < 0) + return irq; + + err = devm_request_irq(iommu->dev, irq, rk_iommu_irq, + IRQF_SHARED, dev_name(dev), iommu); + if (err) { + pm_runtime_disable(dev); + goto err_remove_sysfs; + } + } + return 0; err_remove_sysfs: iommu_device_sysfs_remove(&iommu->iommu); diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index a004f6da35f2..7b1361d57a17 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -377,7 +377,6 @@ static const struct iommu_ops gart_iommu_ops = { .remove_device = gart_iommu_remove_device, .device_group = generic_device_group, .map = gart_iommu_map, - .map_sg = default_iommu_map_sg, .unmap = gart_iommu_unmap, .iova_to_phys = gart_iommu_iova_to_phys, .pgsize_bitmap = GART_IOMMU_PGSIZES, diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 44d40bc771b5..0d03341317c4 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -876,7 +876,6 @@ static const struct iommu_ops tegra_smmu_ops = { .device_group = tegra_smmu_device_group, .map = tegra_smmu_map, .unmap = tegra_smmu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = tegra_smmu_iova_to_phys, .of_xlate = tegra_smmu_of_xlate, .pgsize_bitmap = SZ_4K, diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index faf734ff4cf3..0f6e30e9009d 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -217,6 +217,7 @@ static int bcm7038_l1_set_affinity(struct irq_data *d, return 0; } +#ifdef CONFIG_SMP static void bcm7038_l1_cpu_offline(struct irq_data *d) { struct cpumask *mask = irq_data_get_affinity_mask(d); @@ -241,6 +242,7 @@ static void bcm7038_l1_cpu_offline(struct irq_data *d) } irq_set_affinity_locked(d, &new_affinity, false); } +#endif static int __init bcm7038_l1_init_one(struct device_node *dn, unsigned int idx, @@ -293,7 +295,9 @@ static struct irq_chip bcm7038_l1_irq_chip = { .irq_mask = bcm7038_l1_mask, .irq_unmask = bcm7038_l1_unmask, .irq_set_affinity = bcm7038_l1_set_affinity, +#ifdef CONFIG_SMP .irq_cpu_offline = bcm7038_l1_cpu_offline, +#endif }; static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e214181b77b7..d5912f1ec884 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -861,7 +861,9 @@ static struct irq_chip gic_chip = { .irq_set_affinity = gic_set_affinity, .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, }; static struct irq_chip gic_eoimode1_chip = { @@ -874,7 +876,9 @@ static struct irq_chip gic_eoimode1_chip = { .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, .irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity, - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, }; #define GIC_ID_NR (1U << GICD_TYPER_ID_BITS(gic_data.rdists.gicd_typer)) diff --git a/drivers/irqchip/irq-renesas-h8s.c b/drivers/irqchip/irq-renesas-h8s.c index aed31afb0216..85234d456638 100644 --- a/drivers/irqchip/irq-renesas-h8s.c +++ b/drivers/irqchip/irq-renesas-h8s.c @@ -12,7 +12,7 @@ #include <asm/io.h> static void *intc_baseaddr; -#define IPRA ((unsigned long)intc_baseaddr) +#define IPRA (intc_baseaddr) static const unsigned char ipr_table[] = { 0x03, 0x02, 0x01, 0x00, 0x13, 0x12, 0x11, 0x10, /* 16 - 23 */ @@ -34,7 +34,7 @@ static const unsigned char ipr_table[] = { static void h8s_disable_irq(struct irq_data *data) { int pos; - unsigned int addr; + void __iomem *addr; unsigned short pri; int irq = data->irq; @@ -48,7 +48,7 @@ static void h8s_disable_irq(struct irq_data *data) static void h8s_enable_irq(struct irq_data *data) { int pos; - unsigned int addr; + void __iomem *addr; unsigned short pri; int irq = data->irq; diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index f6fd57ebe6e6..c19766fe8a1a 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -250,7 +250,7 @@ static int s3c_irqext0_type(struct irq_data *data, unsigned int type) void __iomem *gpcon_reg; unsigned long gpcon_offset, extint_offset; - if ((data->hwirq >= 0) && (data->hwirq <= 3)) { + if (data->hwirq <= 3) { gpcon_reg = S3C2410_GPFCON; extint_reg = S3C24XX_EXTINT0; gpcon_offset = (data->hwirq) * 2; diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 3df527fcf4e1..0a2088e12d96 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -603,17 +603,24 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, sizeof(struct stm32_exti_chip_data), GFP_KERNEL); if (!host_data->chips_data) - return NULL; + goto free_host_data; host_data->base = of_iomap(node, 0); if (!host_data->base) { pr_err("%pOF: Unable to map registers\n", node); - return NULL; + goto free_chips_data; } stm32_host_data = host_data; return host_data; + +free_chips_data: + kfree(host_data->chips_data); +free_host_data: + kfree(host_data); + + return NULL; } static struct @@ -665,10 +672,8 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, struct irq_domain *domain; host_data = stm32_exti_host_init(drv_data, node); - if (!host_data) { - ret = -ENOMEM; - goto out_free_mem; - } + if (!host_data) + return -ENOMEM; domain = irq_domain_add_linear(node, drv_data->bank_nr * IRQS_PER_BANK, &irq_exti_domain_ops, NULL); @@ -725,7 +730,6 @@ out_free_domain: irq_domain_remove(domain); out_unmap: iounmap(host_data->base); -out_free_mem: kfree(host_data->chips_data); kfree(host_data); return ret; @@ -752,10 +756,8 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, } host_data = stm32_exti_host_init(drv_data, node); - if (!host_data) { - ret = -ENOMEM; - goto out_free_mem; - } + if (!host_data) + return -ENOMEM; for (i = 0; i < drv_data->bank_nr; i++) stm32_exti_chip_init(host_data, i, node); @@ -777,7 +779,6 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, out_unmap: iounmap(host_data->base); -out_free_mem: kfree(host_data->chips_data); kfree(host_data); return ret; diff --git a/drivers/irqchip/irq-tango.c b/drivers/irqchip/irq-tango.c index 0c085303a583..580e2d72b9ba 100644 --- a/drivers/irqchip/irq-tango.c +++ b/drivers/irqchip/irq-tango.c @@ -205,8 +205,7 @@ static int __init tangox_irq_init(void __iomem *base, struct resource *baseres, tangox_irq_domain_init(dom); - irq_set_chained_handler(irq, tangox_irq_handler); - irq_set_handler_data(irq, dom); + irq_set_chained_handler_and_data(irq, tangox_irq_handler, dom); return 0; } diff --git a/drivers/irqchip/irq-xtensa-mx.c b/drivers/irqchip/irq-xtensa-mx.c index a15a9510c904..e539500752d4 100644 --- a/drivers/irqchip/irq-xtensa-mx.c +++ b/drivers/irqchip/irq-xtensa-mx.c @@ -98,14 +98,12 @@ static void xtensa_mx_irq_unmask(struct irq_data *d) static void xtensa_mx_irq_enable(struct irq_data *d) { - variant_irq_enable(d->hwirq); xtensa_mx_irq_unmask(d); } static void xtensa_mx_irq_disable(struct irq_data *d) { xtensa_mx_irq_mask(d); - variant_irq_disable(d->hwirq); } static void xtensa_mx_irq_ack(struct irq_data *d) diff --git a/drivers/irqchip/irq-xtensa-pic.c b/drivers/irqchip/irq-xtensa-pic.c index f728755fa292..000cb5462bcf 100644 --- a/drivers/irqchip/irq-xtensa-pic.c +++ b/drivers/irqchip/irq-xtensa-pic.c @@ -55,14 +55,12 @@ static void xtensa_irq_unmask(struct irq_data *d) static void xtensa_irq_enable(struct irq_data *d) { - variant_irq_enable(d->hwirq); xtensa_irq_unmask(d); } static void xtensa_irq_disable(struct irq_data *d) { xtensa_irq_mask(d); - variant_irq_disable(d->hwirq); } static void xtensa_irq_ack(struct irq_data *d) diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 68dcbcb4fc5b..8c744578122a 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -432,7 +432,6 @@ static struct i2c_driver g4fan_driver = { .driver = { .name = "therm_windtunnel", }, - .attach_adapter = do_attach, .probe = do_probe, .remove = do_remove, .id_table = therm_windtunnel_id, @@ -445,7 +444,29 @@ static struct i2c_driver g4fan_driver = { static int therm_of_probe(struct platform_device *dev) { - return i2c_add_driver( &g4fan_driver ); + struct i2c_adapter *adap; + int ret, i = 0; + + adap = i2c_get_adapter(0); + if (!adap) + return -EPROBE_DEFER; + + ret = i2c_add_driver(&g4fan_driver); + if (ret) { + i2c_put_adapter(adap); + return ret; + } + + /* We assume Macs have consecutive I2C bus numbers starting at 0 */ + while (adap) { + do_attach(adap); + if (x.running) + return 0; + i2c_put_adapter(adap); + adap = i2c_get_adapter(++i); + } + + return -ENODEV; } static int diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig index 17bf109c58e9..f6e0a8b3a61e 100644 --- a/drivers/md/bcache/Kconfig +++ b/drivers/md/bcache/Kconfig @@ -1,7 +1,8 @@ config BCACHE tristate "Block device as cache" - ---help--- + select CRC64 + help Allows a block device to be used as cache for other devices; uses a btree for indexing and the layout is optimized for SSDs. @@ -10,7 +11,7 @@ config BCACHE config BCACHE_DEBUG bool "Bcache debugging" depends on BCACHE - ---help--- + help Don't select this option unless you're a developer Enables extra debugging tools, allows expensive runtime checks to be @@ -20,7 +21,7 @@ config BCACHE_CLOSURES_DEBUG bool "Debug closures" depends on BCACHE select DEBUG_FS - ---help--- + help Keeps all active closures in a linked list and provides a debugfs interface to list them, which makes it possible to see asynchronous operations that get stuck. diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 7fa2631b422c..7a28232d868b 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -87,8 +87,8 @@ void bch_rescale_priorities(struct cache_set *c, int sectors) { struct cache *ca; struct bucket *b; - unsigned next = c->nbuckets * c->sb.bucket_size / 1024; - unsigned i; + unsigned int next = c->nbuckets * c->sb.bucket_size / 1024; + unsigned int i; int r; atomic_sub(sectors, &c->rescale); @@ -169,7 +169,7 @@ static void bch_invalidate_one_bucket(struct cache *ca, struct bucket *b) #define bucket_prio(b) \ ({ \ - unsigned min_prio = (INITIAL_PRIO - ca->set->min_prio) / 8; \ + unsigned int min_prio = (INITIAL_PRIO - ca->set->min_prio) / 8; \ \ (b->prio - ca->set->min_prio + min_prio) * GC_SECTORS_USED(b); \ }) @@ -244,6 +244,7 @@ static void invalidate_buckets_random(struct cache *ca) while (!fifo_full(&ca->free_inc)) { size_t n; + get_random_bytes(&n, sizeof(n)); n %= (size_t) (ca->sb.nbuckets - ca->sb.first_bucket); @@ -301,7 +302,7 @@ do { \ static int bch_allocator_push(struct cache *ca, long bucket) { - unsigned i; + unsigned int i; /* Prios/gens are actually the most important reserve */ if (fifo_push(&ca->free[RESERVE_PRIO], bucket)) @@ -385,7 +386,7 @@ out: /* Allocation */ -long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait) +long bch_bucket_alloc(struct cache *ca, unsigned int reserve, bool wait) { DEFINE_WAIT(w); struct bucket *b; @@ -421,7 +422,7 @@ out: if (expensive_debug_checks(ca->set)) { size_t iter; long i; - unsigned j; + unsigned int j; for (iter = 0; iter < prio_buckets(ca) * 2; iter++) BUG_ON(ca->prio_buckets[iter] == (uint64_t) r); @@ -470,14 +471,14 @@ void __bch_bucket_free(struct cache *ca, struct bucket *b) void bch_bucket_free(struct cache_set *c, struct bkey *k) { - unsigned i; + unsigned int i; for (i = 0; i < KEY_PTRS(k); i++) __bch_bucket_free(PTR_CACHE(c, k, i), PTR_BUCKET(c, k, i)); } -int __bch_bucket_alloc_set(struct cache_set *c, unsigned reserve, +int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve, struct bkey *k, int n, bool wait) { int i; @@ -510,10 +511,11 @@ err: return -1; } -int bch_bucket_alloc_set(struct cache_set *c, unsigned reserve, +int bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve, struct bkey *k, int n, bool wait) { int ret; + mutex_lock(&c->bucket_lock); ret = __bch_bucket_alloc_set(c, reserve, k, n, wait); mutex_unlock(&c->bucket_lock); @@ -524,8 +526,8 @@ int bch_bucket_alloc_set(struct cache_set *c, unsigned reserve, struct open_bucket { struct list_head list; - unsigned last_write_point; - unsigned sectors_free; + unsigned int last_write_point; + unsigned int sectors_free; BKEY_PADDED(key); }; @@ -556,7 +558,7 @@ struct open_bucket { */ static struct open_bucket *pick_data_bucket(struct cache_set *c, const struct bkey *search, - unsigned write_point, + unsigned int write_point, struct bkey *alloc) { struct open_bucket *ret, *ret_task = NULL; @@ -595,12 +597,16 @@ found: * * If s->writeback is true, will not fail. */ -bool bch_alloc_sectors(struct cache_set *c, struct bkey *k, unsigned sectors, - unsigned write_point, unsigned write_prio, bool wait) +bool bch_alloc_sectors(struct cache_set *c, + struct bkey *k, + unsigned int sectors, + unsigned int write_point, + unsigned int write_prio, + bool wait) { struct open_bucket *b; BKEY_PADDED(key) alloc; - unsigned i; + unsigned int i; /* * We might have to allocate a new bucket, which we can't do with a @@ -613,7 +619,7 @@ bool bch_alloc_sectors(struct cache_set *c, struct bkey *k, unsigned sectors, spin_lock(&c->data_bucket_lock); while (!(b = pick_data_bucket(c, k, write_point, &alloc.key))) { - unsigned watermark = write_prio + unsigned int watermark = write_prio ? RESERVE_MOVINGGC : RESERVE_NONE; @@ -702,6 +708,7 @@ int bch_open_buckets_alloc(struct cache_set *c) for (i = 0; i < MAX_OPEN_BUCKETS; i++) { struct open_bucket *b = kzalloc(sizeof(*b), GFP_KERNEL); + if (!b) return -ENOMEM; diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 05f82ff6f016..83504dd8100a 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -252,7 +252,7 @@ struct bcache_device { struct kobject kobj; struct cache_set *c; - unsigned id; + unsigned int id; #define BCACHEDEVNAME_SIZE 12 char name[BCACHEDEVNAME_SIZE]; @@ -264,18 +264,19 @@ struct bcache_device { #define BCACHE_DEV_UNLINK_DONE 2 #define BCACHE_DEV_WB_RUNNING 3 #define BCACHE_DEV_RATE_DW_RUNNING 4 - unsigned nr_stripes; - unsigned stripe_size; + unsigned int nr_stripes; + unsigned int stripe_size; atomic_t *stripe_sectors_dirty; unsigned long *full_dirty_stripes; struct bio_set bio_split; - unsigned data_csum:1; + unsigned int data_csum:1; - int (*cache_miss)(struct btree *, struct search *, - struct bio *, unsigned); - int (*ioctl) (struct bcache_device *, fmode_t, unsigned, unsigned long); + int (*cache_miss)(struct btree *b, struct search *s, + struct bio *bio, unsigned int sectors); + int (*ioctl)(struct bcache_device *d, fmode_t mode, + unsigned int cmd, unsigned long arg); }; struct io { @@ -284,7 +285,7 @@ struct io { struct list_head lru; unsigned long jiffies; - unsigned sequential; + unsigned int sequential; sector_t last; }; @@ -358,18 +359,18 @@ struct cached_dev { struct cache_accounting accounting; /* The rest of this all shows up in sysfs */ - unsigned sequential_cutoff; - unsigned readahead; + unsigned int sequential_cutoff; + unsigned int readahead; - unsigned io_disable:1; - unsigned verify:1; - unsigned bypass_torture_test:1; + unsigned int io_disable:1; + unsigned int verify:1; + unsigned int bypass_torture_test:1; - unsigned partial_stripes_expensive:1; - unsigned writeback_metadata:1; - unsigned writeback_running:1; + unsigned int partial_stripes_expensive:1; + unsigned int writeback_metadata:1; + unsigned int writeback_running:1; unsigned char writeback_percent; - unsigned writeback_delay; + unsigned int writeback_delay; uint64_t writeback_rate_target; int64_t writeback_rate_proportional; @@ -377,16 +378,16 @@ struct cached_dev { int64_t writeback_rate_integral_scaled; int32_t writeback_rate_change; - unsigned writeback_rate_update_seconds; - unsigned writeback_rate_i_term_inverse; - unsigned writeback_rate_p_term_inverse; - unsigned writeback_rate_minimum; + unsigned int writeback_rate_update_seconds; + unsigned int writeback_rate_i_term_inverse; + unsigned int writeback_rate_p_term_inverse; + unsigned int writeback_rate_minimum; enum stop_on_failure stop_when_cache_set_failed; #define DEFAULT_CACHED_DEV_ERROR_LIMIT 64 atomic_t io_errors; - unsigned error_limit; - unsigned offline_seconds; + unsigned int error_limit; + unsigned int offline_seconds; char backing_dev_name[BDEVNAME_SIZE]; }; @@ -447,7 +448,7 @@ struct cache { * until a gc finishes - otherwise we could pointlessly burn a ton of * cpu */ - unsigned invalidate_needs_gc; + unsigned int invalidate_needs_gc; bool discard; /* Get rid of? */ @@ -472,7 +473,7 @@ struct gc_stat { size_t nkeys; uint64_t data; /* sectors */ - unsigned in_use; /* percent */ + unsigned int in_use; /* percent */ }; /* @@ -518,7 +519,7 @@ struct cache_set { int caches_loaded; struct bcache_device **devices; - unsigned devices_max_used; + unsigned int devices_max_used; atomic_t attached_dev_nr; struct list_head cached_devs; uint64_t cached_dev_sectors; @@ -548,7 +549,7 @@ struct cache_set { * Default number of pages for a new btree node - may be less than a * full bucket */ - unsigned btree_pages; + unsigned int btree_pages; /* * Lists of struct btrees; lru is the list for structs that have memory @@ -571,7 +572,7 @@ struct cache_set { struct list_head btree_cache_freed; /* Number of elements in btree_cache + btree_cache_freeable lists */ - unsigned btree_cache_used; + unsigned int btree_cache_used; /* * If we need to allocate memory for a new btree node and that @@ -613,8 +614,8 @@ struct cache_set { uint16_t min_prio; /* - * max(gen - last_gc) for all buckets. When it gets too big we have to gc - * to keep gens from wrapping around. + * max(gen - last_gc) for all buckets. When it gets too big we have to + * gc to keep gens from wrapping around. */ uint8_t need_gc; struct gc_stat gc_stats; @@ -649,7 +650,7 @@ struct cache_set { struct mutex verify_lock; #endif - unsigned nr_uuids; + unsigned int nr_uuids; struct uuid_entry *uuids; BKEY_PADDED(uuid_bucket); struct closure uuid_write; @@ -670,12 +671,12 @@ struct cache_set { struct journal journal; #define CONGESTED_MAX 1024 - unsigned congested_last_us; + unsigned int congested_last_us; atomic_t congested; /* The rest of this all shows up in sysfs */ - unsigned congested_read_threshold_us; - unsigned congested_write_threshold_us; + unsigned int congested_read_threshold_us; + unsigned int congested_write_threshold_us; struct time_stats btree_gc_time; struct time_stats btree_split_time; @@ -694,16 +695,16 @@ struct cache_set { ON_ERROR_PANIC, } on_error; #define DEFAULT_IO_ERROR_LIMIT 8 - unsigned error_limit; - unsigned error_decay; + unsigned int error_limit; + unsigned int error_decay; unsigned short journal_delay_ms; bool expensive_debug_checks; - unsigned verify:1; - unsigned key_merging_disabled:1; - unsigned gc_always_rewrite:1; - unsigned shrinker_disabled:1; - unsigned copy_gc_enabled:1; + unsigned int verify:1; + unsigned int key_merging_disabled:1; + unsigned int gc_always_rewrite:1; + unsigned int shrinker_disabled:1; + unsigned int copy_gc_enabled:1; #define BUCKET_HASH_BITS 12 struct hlist_head bucket_hash[1 << BUCKET_HASH_BITS]; @@ -712,7 +713,7 @@ struct cache_set { }; struct bbio { - unsigned submit_time_us; + unsigned int submit_time_us; union { struct bkey key; uint64_t _pad[3]; @@ -729,10 +730,10 @@ struct bbio { #define btree_bytes(c) ((c)->btree_pages * PAGE_SIZE) #define btree_blocks(b) \ - ((unsigned) (KEY_SIZE(&b->key) >> (b)->c->block_bits)) + ((unsigned int) (KEY_SIZE(&b->key) >> (b)->c->block_bits)) #define btree_default_blocks(c) \ - ((unsigned) ((PAGE_SECTORS * (c)->btree_pages) >> (c)->block_bits)) + ((unsigned int) ((PAGE_SECTORS * (c)->btree_pages) >> (c)->block_bits)) #define bucket_pages(c) ((c)->sb.bucket_size / PAGE_SECTORS) #define bucket_bytes(c) ((c)->sb.bucket_size << 9) @@ -761,21 +762,21 @@ static inline sector_t bucket_remainder(struct cache_set *c, sector_t s) static inline struct cache *PTR_CACHE(struct cache_set *c, const struct bkey *k, - unsigned ptr) + unsigned int ptr) { return c->cache[PTR_DEV(k, ptr)]; } static inline size_t PTR_BUCKET_NR(struct cache_set *c, const struct bkey *k, - unsigned ptr) + unsigned int ptr) { return sector_to_bucket(c, PTR_OFFSET(k, ptr)); } static inline struct bucket *PTR_BUCKET(struct cache_set *c, const struct bkey *k, - unsigned ptr) + unsigned int ptr) { return PTR_CACHE(c, k, ptr)->buckets + PTR_BUCKET_NR(c, k, ptr); } @@ -783,17 +784,18 @@ static inline struct bucket *PTR_BUCKET(struct cache_set *c, static inline uint8_t gen_after(uint8_t a, uint8_t b) { uint8_t r = a - b; + return r > 128U ? 0 : r; } static inline uint8_t ptr_stale(struct cache_set *c, const struct bkey *k, - unsigned i) + unsigned int i) { return gen_after(PTR_BUCKET(c, k, i)->gen, PTR_GEN(k, i)); } static inline bool ptr_available(struct cache_set *c, const struct bkey *k, - unsigned i) + unsigned int i) { return (PTR_DEV(k, i) < MAX_CACHES_PER_SET) && PTR_CACHE(c, k, i); } @@ -879,16 +881,16 @@ static inline uint8_t bucket_gc_gen(struct bucket *b) #define BUCKET_GC_GEN_MAX 96U #define kobj_attribute_write(n, fn) \ - static struct kobj_attribute ksysfs_##n = __ATTR(n, S_IWUSR, NULL, fn) + static struct kobj_attribute ksysfs_##n = __ATTR(n, 0200, NULL, fn) #define kobj_attribute_rw(n, show, store) \ static struct kobj_attribute ksysfs_##n = \ - __ATTR(n, S_IWUSR|S_IRUSR, show, store) + __ATTR(n, 0600, show, store) static inline void wake_up_allocators(struct cache_set *c) { struct cache *ca; - unsigned i; + unsigned int i; for_each_cache(ca, c, i) wake_up_process(ca->alloc_thread); @@ -924,40 +926,43 @@ static inline void wait_for_kthread_stop(void) /* Forward declarations */ void bch_count_backing_io_errors(struct cached_dev *dc, struct bio *bio); -void bch_count_io_errors(struct cache *, blk_status_t, int, const char *); -void bch_bbio_count_io_errors(struct cache_set *, struct bio *, - blk_status_t, const char *); -void bch_bbio_endio(struct cache_set *, struct bio *, blk_status_t, - const char *); -void bch_bbio_free(struct bio *, struct cache_set *); -struct bio *bch_bbio_alloc(struct cache_set *); - -void __bch_submit_bbio(struct bio *, struct cache_set *); -void bch_submit_bbio(struct bio *, struct cache_set *, struct bkey *, unsigned); - -uint8_t bch_inc_gen(struct cache *, struct bucket *); -void bch_rescale_priorities(struct cache_set *, int); - -bool bch_can_invalidate_bucket(struct cache *, struct bucket *); -void __bch_invalidate_one_bucket(struct cache *, struct bucket *); - -void __bch_bucket_free(struct cache *, struct bucket *); -void bch_bucket_free(struct cache_set *, struct bkey *); - -long bch_bucket_alloc(struct cache *, unsigned, bool); -int __bch_bucket_alloc_set(struct cache_set *, unsigned, - struct bkey *, int, bool); -int bch_bucket_alloc_set(struct cache_set *, unsigned, - struct bkey *, int, bool); -bool bch_alloc_sectors(struct cache_set *, struct bkey *, unsigned, - unsigned, unsigned, bool); +void bch_count_io_errors(struct cache *ca, blk_status_t error, + int is_read, const char *m); +void bch_bbio_count_io_errors(struct cache_set *c, struct bio *bio, + blk_status_t error, const char *m); +void bch_bbio_endio(struct cache_set *c, struct bio *bio, + blk_status_t error, const char *m); +void bch_bbio_free(struct bio *bio, struct cache_set *c); +struct bio *bch_bbio_alloc(struct cache_set *c); + +void __bch_submit_bbio(struct bio *bio, struct cache_set *c); +void bch_submit_bbio(struct bio *bio, struct cache_set *c, + struct bkey *k, unsigned int ptr); + +uint8_t bch_inc_gen(struct cache *ca, struct bucket *b); +void bch_rescale_priorities(struct cache_set *c, int sectors); + +bool bch_can_invalidate_bucket(struct cache *ca, struct bucket *b); +void __bch_invalidate_one_bucket(struct cache *ca, struct bucket *b); + +void __bch_bucket_free(struct cache *ca, struct bucket *b); +void bch_bucket_free(struct cache_set *c, struct bkey *k); + +long bch_bucket_alloc(struct cache *ca, unsigned int reserve, bool wait); +int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve, + struct bkey *k, int n, bool wait); +int bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve, + struct bkey *k, int n, bool wait); +bool bch_alloc_sectors(struct cache_set *c, struct bkey *k, + unsigned int sectors, unsigned int write_point, + unsigned int write_prio, bool wait); bool bch_cached_dev_error(struct cached_dev *dc); __printf(2, 3) -bool bch_cache_set_error(struct cache_set *, const char *, ...); +bool bch_cache_set_error(struct cache_set *c, const char *fmt, ...); -void bch_prio_write(struct cache *); -void bch_write_bdev_super(struct cached_dev *, struct closure *); +void bch_prio_write(struct cache *ca); +void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent); extern struct workqueue_struct *bcache_wq; extern struct mutex bch_register_lock; @@ -969,30 +974,31 @@ extern struct kobj_type bch_cache_set_ktype; extern struct kobj_type bch_cache_set_internal_ktype; extern struct kobj_type bch_cache_ktype; -void bch_cached_dev_release(struct kobject *); -void bch_flash_dev_release(struct kobject *); -void bch_cache_set_release(struct kobject *); -void bch_cache_release(struct kobject *); +void bch_cached_dev_release(struct kobject *kobj); +void bch_flash_dev_release(struct kobject *kobj); +void bch_cache_set_release(struct kobject *kobj); +void bch_cache_release(struct kobject *kobj); -int bch_uuid_write(struct cache_set *); -void bcache_write_super(struct cache_set *); +int bch_uuid_write(struct cache_set *c); +void bcache_write_super(struct cache_set *c); int bch_flash_dev_create(struct cache_set *c, uint64_t size); -int bch_cached_dev_attach(struct cached_dev *, struct cache_set *, uint8_t *); -void bch_cached_dev_detach(struct cached_dev *); -void bch_cached_dev_run(struct cached_dev *); -void bcache_device_stop(struct bcache_device *); - -void bch_cache_set_unregister(struct cache_set *); -void bch_cache_set_stop(struct cache_set *); - -struct cache_set *bch_cache_set_alloc(struct cache_sb *); -void bch_btree_cache_free(struct cache_set *); -int bch_btree_cache_alloc(struct cache_set *); -void bch_moving_init_cache_set(struct cache_set *); -int bch_open_buckets_alloc(struct cache_set *); -void bch_open_buckets_free(struct cache_set *); +int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, + uint8_t *set_uuid); +void bch_cached_dev_detach(struct cached_dev *dc); +void bch_cached_dev_run(struct cached_dev *dc); +void bcache_device_stop(struct bcache_device *d); + +void bch_cache_set_unregister(struct cache_set *c); +void bch_cache_set_stop(struct cache_set *c); + +struct cache_set *bch_cache_set_alloc(struct cache_sb *sb); +void bch_btree_cache_free(struct cache_set *c); +int bch_btree_cache_alloc(struct cache_set *c); +void bch_moving_init_cache_set(struct cache_set *c); +int bch_open_buckets_alloc(struct cache_set *c); +void bch_open_buckets_free(struct cache_set *c); int bch_cache_allocator_start(struct cache *ca); diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index 596c93b44e9b..8f07fa6e1739 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c @@ -18,31 +18,31 @@ #ifdef CONFIG_BCACHE_DEBUG -void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned set) +void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned int set) { struct bkey *k, *next; for (k = i->start; k < bset_bkey_last(i); k = next) { next = bkey_next(k); - printk(KERN_ERR "block %u key %u/%u: ", set, - (unsigned) ((u64 *) k - i->d), i->keys); + pr_err("block %u key %u/%u: ", set, + (unsigned int) ((u64 *) k - i->d), i->keys); if (b->ops->key_dump) b->ops->key_dump(b, k); else - printk("%llu:%llu\n", KEY_INODE(k), KEY_OFFSET(k)); + pr_err("%llu:%llu\n", KEY_INODE(k), KEY_OFFSET(k)); if (next < bset_bkey_last(i) && bkey_cmp(k, b->ops->is_extents ? &START_KEY(next) : next) > 0) - printk(KERN_ERR "Key skipped backwards\n"); + pr_err("Key skipped backwards\n"); } } void bch_dump_bucket(struct btree_keys *b) { - unsigned i; + unsigned int i; console_lock(); for (i = 0; i <= b->nsets; i++) @@ -53,7 +53,7 @@ void bch_dump_bucket(struct btree_keys *b) int __bch_count_data(struct btree_keys *b) { - unsigned ret = 0; + unsigned int ret = 0; struct btree_iter iter; struct bkey *k; @@ -128,7 +128,7 @@ static inline void bch_btree_iter_next_check(struct btree_iter *iter) {} /* Keylists */ -int __bch_keylist_realloc(struct keylist *l, unsigned u64s) +int __bch_keylist_realloc(struct keylist *l, unsigned int u64s) { size_t oldsize = bch_keylist_nkeys(l); size_t newsize = oldsize + u64s; @@ -180,7 +180,7 @@ void bch_keylist_pop_front(struct keylist *l) /* Key/pointer manipulation */ void bch_bkey_copy_single_ptr(struct bkey *dest, const struct bkey *src, - unsigned i) + unsigned int i) { BUG_ON(i > KEY_PTRS(src)); @@ -194,7 +194,7 @@ void bch_bkey_copy_single_ptr(struct bkey *dest, const struct bkey *src, bool __bch_cut_front(const struct bkey *where, struct bkey *k) { - unsigned i, len = 0; + unsigned int i, len = 0; if (bkey_cmp(where, &START_KEY(k)) <= 0) return false; @@ -214,7 +214,7 @@ bool __bch_cut_front(const struct bkey *where, struct bkey *k) bool __bch_cut_back(const struct bkey *where, struct bkey *k) { - unsigned len = 0; + unsigned int len = 0; if (bkey_cmp(where, k) >= 0) return false; @@ -240,9 +240,9 @@ bool __bch_cut_back(const struct bkey *where, struct bkey *k) #define BKEY_MANTISSA_MASK ((1 << BKEY_MANTISSA_BITS) - 1) struct bkey_float { - unsigned exponent:BKEY_EXPONENT_BITS; - unsigned m:BKEY_MID_BITS; - unsigned mantissa:BKEY_MANTISSA_BITS; + unsigned int exponent:BKEY_EXPONENT_BITS; + unsigned int m:BKEY_MID_BITS; + unsigned int mantissa:BKEY_MANTISSA_BITS; } __packed; /* @@ -311,7 +311,9 @@ void bch_btree_keys_free(struct btree_keys *b) } EXPORT_SYMBOL(bch_btree_keys_free); -int bch_btree_keys_alloc(struct btree_keys *b, unsigned page_order, gfp_t gfp) +int bch_btree_keys_alloc(struct btree_keys *b, + unsigned int page_order, + gfp_t gfp) { struct bset_tree *t = b->set; @@ -345,7 +347,7 @@ EXPORT_SYMBOL(bch_btree_keys_alloc); void bch_btree_keys_init(struct btree_keys *b, const struct btree_keys_ops *ops, bool *expensive_debug_checks) { - unsigned i; + unsigned int i; b->ops = ops; b->expensive_debug_checks = expensive_debug_checks; @@ -370,7 +372,7 @@ EXPORT_SYMBOL(bch_btree_keys_init); * return array index next to j when does in-order traverse * of a binary tree which is stored in a linear array */ -static unsigned inorder_next(unsigned j, unsigned size) +static unsigned int inorder_next(unsigned int j, unsigned int size) { if (j * 2 + 1 < size) { j = j * 2 + 1; @@ -387,7 +389,7 @@ static unsigned inorder_next(unsigned j, unsigned size) * return array index previous to j when does in-order traverse * of a binary tree which is stored in a linear array */ -static unsigned inorder_prev(unsigned j, unsigned size) +static unsigned int inorder_prev(unsigned int j, unsigned int size) { if (j * 2 < size) { j = j * 2; @@ -400,7 +402,8 @@ static unsigned inorder_prev(unsigned j, unsigned size) return j; } -/* I have no idea why this code works... and I'm the one who wrote it +/* + * I have no idea why this code works... and I'm the one who wrote it * * However, I do know what it does: * Given a binary tree constructed in an array (i.e. how you normally implement @@ -413,10 +416,12 @@ static unsigned inorder_prev(unsigned j, unsigned size) * extra is a function of size: * extra = (size - rounddown_pow_of_two(size - 1)) << 1; */ -static unsigned __to_inorder(unsigned j, unsigned size, unsigned extra) +static unsigned int __to_inorder(unsigned int j, + unsigned int size, + unsigned int extra) { - unsigned b = fls(j); - unsigned shift = fls(size - 1) - b; + unsigned int b = fls(j); + unsigned int shift = fls(size - 1) - b; j ^= 1U << (b - 1); j <<= 1; @@ -433,14 +438,16 @@ static unsigned __to_inorder(unsigned j, unsigned size, unsigned extra) * Return the cacheline index in bset_tree->data, where j is index * from a linear array which stores the auxiliar binary tree */ -static unsigned to_inorder(unsigned j, struct bset_tree *t) +static unsigned int to_inorder(unsigned int j, struct bset_tree *t) { return __to_inorder(j, t->size, t->extra); } -static unsigned __inorder_to_tree(unsigned j, unsigned size, unsigned extra) +static unsigned int __inorder_to_tree(unsigned int j, + unsigned int size, + unsigned int extra) { - unsigned shift; + unsigned int shift; if (j > extra) j += j - extra; @@ -457,7 +464,7 @@ static unsigned __inorder_to_tree(unsigned j, unsigned size, unsigned extra) * Return an index from a linear array which stores the auxiliar binary * tree, j is the cacheline index of t->data. */ -static unsigned inorder_to_tree(unsigned j, struct bset_tree *t) +static unsigned int inorder_to_tree(unsigned int j, struct bset_tree *t) { return __inorder_to_tree(j, t->size, t->extra); } @@ -468,14 +475,15 @@ void inorder_test(void) unsigned long done = 0; ktime_t start = ktime_get(); - for (unsigned size = 2; + for (unsigned int size = 2; size < 65536000; size++) { - unsigned extra = (size - rounddown_pow_of_two(size - 1)) << 1; - unsigned i = 1, j = rounddown_pow_of_two(size - 1); + unsigned int extra = + (size - rounddown_pow_of_two(size - 1)) << 1; + unsigned int i = 1, j = rounddown_pow_of_two(size - 1); if (!(size % 4096)) - printk(KERN_NOTICE "loop %u, %llu per us\n", size, + pr_notice("loop %u, %llu per us\n", size, done / ktime_us_delta(ktime_get(), start)); while (1) { @@ -518,30 +526,31 @@ void inorder_test(void) * of the previous key so we can walk backwards to it from t->tree[j]'s key. */ -static struct bkey *cacheline_to_bkey(struct bset_tree *t, unsigned cacheline, - unsigned offset) +static struct bkey *cacheline_to_bkey(struct bset_tree *t, + unsigned int cacheline, + unsigned int offset) { return ((void *) t->data) + cacheline * BSET_CACHELINE + offset * 8; } -static unsigned bkey_to_cacheline(struct bset_tree *t, struct bkey *k) +static unsigned int bkey_to_cacheline(struct bset_tree *t, struct bkey *k) { return ((void *) k - (void *) t->data) / BSET_CACHELINE; } -static unsigned bkey_to_cacheline_offset(struct bset_tree *t, - unsigned cacheline, +static unsigned int bkey_to_cacheline_offset(struct bset_tree *t, + unsigned int cacheline, struct bkey *k) { return (u64 *) k - (u64 *) cacheline_to_bkey(t, cacheline, 0); } -static struct bkey *tree_to_bkey(struct bset_tree *t, unsigned j) +static struct bkey *tree_to_bkey(struct bset_tree *t, unsigned int j) { return cacheline_to_bkey(t, to_inorder(j, t), t->tree[j].m); } -static struct bkey *tree_to_prev_bkey(struct bset_tree *t, unsigned j) +static struct bkey *tree_to_prev_bkey(struct bset_tree *t, unsigned int j) { return (void *) (((uint64_t *) tree_to_bkey(t, j)) - t->prev[j]); } @@ -550,7 +559,7 @@ static struct bkey *tree_to_prev_bkey(struct bset_tree *t, unsigned j) * For the write set - the one we're currently inserting keys into - we don't * maintain a full search tree, we just keep a simple lookup table in t->prev. */ -static struct bkey *table_to_bkey(struct bset_tree *t, unsigned cacheline) +static struct bkey *table_to_bkey(struct bset_tree *t, unsigned int cacheline) { return cacheline_to_bkey(t, cacheline, t->prev[cacheline]); } @@ -576,14 +585,15 @@ static inline uint64_t shrd128(uint64_t high, uint64_t low, uint8_t shift) * See make_bfloat() to check when most significant bit of f->exponent * is set or not. */ -static inline unsigned bfloat_mantissa(const struct bkey *k, +static inline unsigned int bfloat_mantissa(const struct bkey *k, struct bkey_float *f) { const uint64_t *p = &k->low - (f->exponent >> 6); + return shrd128(p[-1], p[0], f->exponent & 63) & BKEY_MANTISSA_MASK; } -static void make_bfloat(struct bset_tree *t, unsigned j) +static void make_bfloat(struct bset_tree *t, unsigned int j) { struct bkey_float *f = &t->tree[j]; struct bkey *m = tree_to_bkey(t, j); @@ -631,7 +641,7 @@ static void make_bfloat(struct bset_tree *t, unsigned j) static void bset_alloc_tree(struct btree_keys *b, struct bset_tree *t) { if (t != b->set) { - unsigned j = roundup(t[-1].size, + unsigned int j = roundup(t[-1].size, 64 / sizeof(struct bkey_float)); t->tree = t[-1].tree + j; @@ -686,13 +696,13 @@ void bch_bset_build_written_tree(struct btree_keys *b) { struct bset_tree *t = bset_tree_last(b); struct bkey *prev = NULL, *k = t->data->start; - unsigned j, cacheline = 1; + unsigned int j, cacheline = 1; b->last_set_unwritten = 0; bset_alloc_tree(b, t); - t->size = min_t(unsigned, + t->size = min_t(unsigned int, bkey_to_cacheline(t, bset_bkey_last(t->data)), b->set->tree + btree_keys_cachelines(b) - t->tree); @@ -732,7 +742,7 @@ EXPORT_SYMBOL(bch_bset_build_written_tree); void bch_bset_fix_invalidated_key(struct btree_keys *b, struct bkey *k) { struct bset_tree *t; - unsigned inorder, j = 1; + unsigned int inorder, j = 1; for (t = b->set; t <= bset_tree_last(b); t++) if (k < bset_bkey_last(t->data)) @@ -779,14 +789,15 @@ static void bch_bset_fix_lookup_table(struct btree_keys *b, struct bset_tree *t, struct bkey *k) { - unsigned shift = bkey_u64s(k); - unsigned j = bkey_to_cacheline(t, k); + unsigned int shift = bkey_u64s(k); + unsigned int j = bkey_to_cacheline(t, k); /* We're getting called from btree_split() or btree_gc, just bail out */ if (!t->size) return; - /* k is the key we just inserted; we need to find the entry in the + /* + * k is the key we just inserted; we need to find the entry in the * lookup table for the first key that is strictly greater than k: * it's either k's cacheline or the next one */ @@ -794,7 +805,8 @@ static void bch_bset_fix_lookup_table(struct btree_keys *b, table_to_bkey(t, j) <= k) j++; - /* Adjust all the lookup table entries, and find a new key for any that + /* + * Adjust all the lookup table entries, and find a new key for any that * have gotten too big */ for (; j < t->size; j++) { @@ -819,7 +831,8 @@ static void bch_bset_fix_lookup_table(struct btree_keys *b, k != bset_bkey_last(t->data); k = bkey_next(k)) if (t->size == bkey_to_cacheline(t, k)) { - t->prev[t->size] = bkey_to_cacheline_offset(t, t->size, k); + t->prev[t->size] = + bkey_to_cacheline_offset(t, t->size, k); t->size++; } } @@ -867,10 +880,10 @@ void bch_bset_insert(struct btree_keys *b, struct bkey *where, } EXPORT_SYMBOL(bch_bset_insert); -unsigned bch_btree_insert_key(struct btree_keys *b, struct bkey *k, +unsigned int bch_btree_insert_key(struct btree_keys *b, struct bkey *k, struct bkey *replace_key) { - unsigned status = BTREE_INSERT_STATUS_NO_INSERT; + unsigned int status = BTREE_INSERT_STATUS_NO_INSERT; struct bset *i = bset_tree_last(b)->data; struct bkey *m, *prev = NULL; struct btree_iter iter; @@ -922,10 +935,10 @@ struct bset_search_iter { static struct bset_search_iter bset_search_write_set(struct bset_tree *t, const struct bkey *search) { - unsigned li = 0, ri = t->size; + unsigned int li = 0, ri = t->size; while (li + 1 != ri) { - unsigned m = (li + ri) >> 1; + unsigned int m = (li + ri) >> 1; if (bkey_cmp(table_to_bkey(t, m), search) > 0) ri = m; @@ -944,7 +957,7 @@ static struct bset_search_iter bset_search_tree(struct bset_tree *t, { struct bkey *l, *r; struct bkey_float *f; - unsigned inorder, j, n = 1; + unsigned int inorder, j, n = 1; do { /* @@ -958,7 +971,8 @@ static struct bset_search_iter bset_search_tree(struct bset_tree *t, * p = 0; * but a branch instruction is avoided. */ - unsigned p = n << 4; + unsigned int p = n << 4; + p &= ((int) (p - t->size)) >> 31; prefetch(&t->tree[p]); @@ -978,7 +992,7 @@ static struct bset_search_iter bset_search_tree(struct bset_tree *t, * to work - that's done in make_bfloat() */ if (likely(f->exponent != 127)) - n = j * 2 + (((unsigned) + n = j * 2 + (((unsigned int) (f->mantissa - bfloat_mantissa(search, f))) >> 31); else @@ -1109,6 +1123,7 @@ static struct bkey *__bch_btree_iter_init(struct btree_keys *b, struct bset_tree *start) { struct bkey *ret = NULL; + iter->size = ARRAY_SIZE(iter->data); iter->used = 0; @@ -1184,7 +1199,8 @@ void bch_bset_sort_state_free(struct bset_sort_state *state) mempool_exit(&state->pool); } -int bch_bset_sort_state_init(struct bset_sort_state *state, unsigned page_order) +int bch_bset_sort_state_init(struct bset_sort_state *state, + unsigned int page_order) { spin_lock_init(&state->time.lock); @@ -1237,7 +1253,7 @@ static void btree_mergesort(struct btree_keys *b, struct bset *out, } static void __btree_sort(struct btree_keys *b, struct btree_iter *iter, - unsigned start, unsigned order, bool fixup, + unsigned int start, unsigned int order, bool fixup, struct bset_sort_state *state) { uint64_t start_time; @@ -1288,7 +1304,7 @@ static void __btree_sort(struct btree_keys *b, struct btree_iter *iter, bch_time_stats_update(&state->time, start_time); } -void bch_btree_sort_partial(struct btree_keys *b, unsigned start, +void bch_btree_sort_partial(struct btree_keys *b, unsigned int start, struct bset_sort_state *state) { size_t order = b->page_order, keys = 0; @@ -1298,7 +1314,7 @@ void bch_btree_sort_partial(struct btree_keys *b, unsigned start, __bch_btree_iter_init(b, &iter, NULL, &b->set[start]); if (start) { - unsigned i; + unsigned int i; for (i = start; i <= b->nsets; i++) keys += b->set[i].data->keys; @@ -1323,8 +1339,8 @@ void bch_btree_sort_into(struct btree_keys *b, struct btree_keys *new, struct bset_sort_state *state) { uint64_t start_time = local_clock(); - struct btree_iter iter; + bch_btree_iter_init(b, &iter, NULL); btree_mergesort(b, new->set->data, &iter, false, true); @@ -1338,7 +1354,7 @@ void bch_btree_sort_into(struct btree_keys *b, struct btree_keys *new, void bch_btree_sort_lazy(struct btree_keys *b, struct bset_sort_state *state) { - unsigned crit = SORT_CRIT; + unsigned int crit = SORT_CRIT; int i; /* Don't sort if nothing to do */ @@ -1367,7 +1383,7 @@ EXPORT_SYMBOL(bch_btree_sort_lazy); void bch_btree_keys_stats(struct btree_keys *b, struct bset_stats *stats) { - unsigned i; + unsigned int i; for (i = 0; i <= b->nsets; i++) { struct bset_tree *t = &b->set[i]; diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h index b867f2200495..bac76aabca6d 100644 --- a/drivers/md/bcache/bset.h +++ b/drivers/md/bcache/bset.h @@ -163,10 +163,10 @@ struct bset_tree { */ /* size of the binary tree and prev array */ - unsigned size; + unsigned int size; /* function of size - precalculated for to_inorder() */ - unsigned extra; + unsigned int extra; /* copy of the last key in the set */ struct bkey end; @@ -187,18 +187,25 @@ struct bset_tree { }; struct btree_keys_ops { - bool (*sort_cmp)(struct btree_iter_set, - struct btree_iter_set); - struct bkey *(*sort_fixup)(struct btree_iter *, struct bkey *); - bool (*insert_fixup)(struct btree_keys *, struct bkey *, - struct btree_iter *, struct bkey *); - bool (*key_invalid)(struct btree_keys *, - const struct bkey *); - bool (*key_bad)(struct btree_keys *, const struct bkey *); - bool (*key_merge)(struct btree_keys *, - struct bkey *, struct bkey *); - void (*key_to_text)(char *, size_t, const struct bkey *); - void (*key_dump)(struct btree_keys *, const struct bkey *); + bool (*sort_cmp)(struct btree_iter_set l, + struct btree_iter_set r); + struct bkey *(*sort_fixup)(struct btree_iter *iter, + struct bkey *tmp); + bool (*insert_fixup)(struct btree_keys *b, + struct bkey *insert, + struct btree_iter *iter, + struct bkey *replace_key); + bool (*key_invalid)(struct btree_keys *bk, + const struct bkey *k); + bool (*key_bad)(struct btree_keys *bk, + const struct bkey *k); + bool (*key_merge)(struct btree_keys *bk, + struct bkey *l, struct bkey *r); + void (*key_to_text)(char *buf, + size_t size, + const struct bkey *k); + void (*key_dump)(struct btree_keys *keys, + const struct bkey *k); /* * Only used for deciding whether to use START_KEY(k) or just the key @@ -211,7 +218,7 @@ struct btree_keys { const struct btree_keys_ops *ops; uint8_t page_order; uint8_t nsets; - unsigned last_set_unwritten:1; + unsigned int last_set_unwritten:1; bool *expensive_debug_checks; /* @@ -239,12 +246,14 @@ static inline bool bkey_written(struct btree_keys *b, struct bkey *k) return !b->last_set_unwritten || k < b->set[b->nsets].data->start; } -static inline unsigned bset_byte_offset(struct btree_keys *b, struct bset *i) +static inline unsigned int bset_byte_offset(struct btree_keys *b, + struct bset *i) { return ((size_t) i) - ((size_t) b->set->data); } -static inline unsigned bset_sector_offset(struct btree_keys *b, struct bset *i) +static inline unsigned int bset_sector_offset(struct btree_keys *b, + struct bset *i) { return bset_byte_offset(b, i) >> 9; } @@ -273,25 +282,27 @@ static inline size_t bch_btree_keys_u64s_remaining(struct btree_keys *b) } static inline struct bset *bset_next_set(struct btree_keys *b, - unsigned block_bytes) + unsigned int block_bytes) { struct bset *i = bset_tree_last(b)->data; return ((void *) i) + roundup(set_bytes(i), block_bytes); } -void bch_btree_keys_free(struct btree_keys *); -int bch_btree_keys_alloc(struct btree_keys *, unsigned, gfp_t); -void bch_btree_keys_init(struct btree_keys *, const struct btree_keys_ops *, - bool *); - -void bch_bset_init_next(struct btree_keys *, struct bset *, uint64_t); -void bch_bset_build_written_tree(struct btree_keys *); -void bch_bset_fix_invalidated_key(struct btree_keys *, struct bkey *); -bool bch_bkey_try_merge(struct btree_keys *, struct bkey *, struct bkey *); -void bch_bset_insert(struct btree_keys *, struct bkey *, struct bkey *); -unsigned bch_btree_insert_key(struct btree_keys *, struct bkey *, - struct bkey *); +void bch_btree_keys_free(struct btree_keys *b); +int bch_btree_keys_alloc(struct btree_keys *b, unsigned int page_order, + gfp_t gfp); +void bch_btree_keys_init(struct btree_keys *b, const struct btree_keys_ops *ops, + bool *expensive_debug_checks); + +void bch_bset_init_next(struct btree_keys *b, struct bset *i, uint64_t magic); +void bch_bset_build_written_tree(struct btree_keys *b); +void bch_bset_fix_invalidated_key(struct btree_keys *b, struct bkey *k); +bool bch_bkey_try_merge(struct btree_keys *b, struct bkey *l, struct bkey *r); +void bch_bset_insert(struct btree_keys *b, struct bkey *where, + struct bkey *insert); +unsigned int bch_btree_insert_key(struct btree_keys *b, struct bkey *k, + struct bkey *replace_key); enum { BTREE_INSERT_STATUS_NO_INSERT = 0, @@ -313,18 +324,21 @@ struct btree_iter { } data[MAX_BSETS]; }; -typedef bool (*ptr_filter_fn)(struct btree_keys *, const struct bkey *); +typedef bool (*ptr_filter_fn)(struct btree_keys *b, const struct bkey *k); -struct bkey *bch_btree_iter_next(struct btree_iter *); -struct bkey *bch_btree_iter_next_filter(struct btree_iter *, - struct btree_keys *, ptr_filter_fn); +struct bkey *bch_btree_iter_next(struct btree_iter *iter); +struct bkey *bch_btree_iter_next_filter(struct btree_iter *iter, + struct btree_keys *b, + ptr_filter_fn fn); -void bch_btree_iter_push(struct btree_iter *, struct bkey *, struct bkey *); -struct bkey *bch_btree_iter_init(struct btree_keys *, struct btree_iter *, - struct bkey *); +void bch_btree_iter_push(struct btree_iter *iter, struct bkey *k, + struct bkey *end); +struct bkey *bch_btree_iter_init(struct btree_keys *b, + struct btree_iter *iter, + struct bkey *search); -struct bkey *__bch_bset_search(struct btree_keys *, struct bset_tree *, - const struct bkey *); +struct bkey *__bch_bset_search(struct btree_keys *b, struct bset_tree *t, + const struct bkey *search); /* * Returns the first key that is strictly greater than search @@ -349,21 +363,23 @@ static inline struct bkey *bch_bset_search(struct btree_keys *b, struct bset_sort_state { mempool_t pool; - unsigned page_order; - unsigned crit_factor; + unsigned int page_order; + unsigned int crit_factor; struct time_stats time; }; -void bch_bset_sort_state_free(struct bset_sort_state *); -int bch_bset_sort_state_init(struct bset_sort_state *, unsigned); -void bch_btree_sort_lazy(struct btree_keys *, struct bset_sort_state *); -void bch_btree_sort_into(struct btree_keys *, struct btree_keys *, - struct bset_sort_state *); -void bch_btree_sort_and_fix_extents(struct btree_keys *, struct btree_iter *, - struct bset_sort_state *); -void bch_btree_sort_partial(struct btree_keys *, unsigned, - struct bset_sort_state *); +void bch_bset_sort_state_free(struct bset_sort_state *state); +int bch_bset_sort_state_init(struct bset_sort_state *state, + unsigned int page_order); +void bch_btree_sort_lazy(struct btree_keys *b, struct bset_sort_state *state); +void bch_btree_sort_into(struct btree_keys *b, struct btree_keys *new, + struct bset_sort_state *state); +void bch_btree_sort_and_fix_extents(struct btree_keys *b, + struct btree_iter *iter, + struct bset_sort_state *state); +void bch_btree_sort_partial(struct btree_keys *b, unsigned int start, + struct bset_sort_state *state); static inline void bch_btree_sort(struct btree_keys *b, struct bset_sort_state *state) @@ -377,13 +393,13 @@ struct bset_stats { size_t floats, failed; }; -void bch_btree_keys_stats(struct btree_keys *, struct bset_stats *); +void bch_btree_keys_stats(struct btree_keys *b, struct bset_stats *state); /* Bkey utility code */ #define bset_bkey_last(i) bkey_idx((struct bkey *) (i)->d, (i)->keys) -static inline struct bkey *bset_bkey_idx(struct bset *i, unsigned idx) +static inline struct bkey *bset_bkey_idx(struct bset *i, unsigned int idx) { return bkey_idx(i->start, idx); } @@ -401,10 +417,10 @@ static __always_inline int64_t bkey_cmp(const struct bkey *l, : (int64_t) KEY_OFFSET(l) - (int64_t) KEY_OFFSET(r); } -void bch_bkey_copy_single_ptr(struct bkey *, const struct bkey *, - unsigned); -bool __bch_cut_front(const struct bkey *, struct bkey *); -bool __bch_cut_back(const struct bkey *, struct bkey *); +void bch_bkey_copy_single_ptr(struct bkey *dest, const struct bkey *src, + unsigned int i); +bool __bch_cut_front(const struct bkey *where, struct bkey *k); +bool __bch_cut_back(const struct bkey *where, struct bkey *k); static inline bool bch_cut_front(const struct bkey *where, struct bkey *k) { @@ -522,18 +538,20 @@ static inline size_t bch_keylist_bytes(struct keylist *l) return bch_keylist_nkeys(l) * sizeof(uint64_t); } -struct bkey *bch_keylist_pop(struct keylist *); -void bch_keylist_pop_front(struct keylist *); -int __bch_keylist_realloc(struct keylist *, unsigned); +struct bkey *bch_keylist_pop(struct keylist *l); +void bch_keylist_pop_front(struct keylist *l); +int __bch_keylist_realloc(struct keylist *l, unsigned int u64s); /* Debug stuff */ #ifdef CONFIG_BCACHE_DEBUG -int __bch_count_data(struct btree_keys *); -void __printf(2, 3) __bch_check_keys(struct btree_keys *, const char *, ...); -void bch_dump_bset(struct btree_keys *, struct bset *, unsigned); -void bch_dump_bucket(struct btree_keys *); +int __bch_count_data(struct btree_keys *b); +void __printf(2, 3) __bch_check_keys(struct btree_keys *b, + const char *fmt, + ...); +void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned int set); +void bch_dump_bucket(struct btree_keys *b); #else @@ -541,7 +559,7 @@ static inline int __bch_count_data(struct btree_keys *b) { return -1; } static inline void __printf(2, 3) __bch_check_keys(struct btree_keys *b, const char *fmt, ...) {} static inline void bch_dump_bucket(struct btree_keys *b) {} -void bch_dump_bset(struct btree_keys *, struct bset *, unsigned); +void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned int set); #endif diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index c19f7716df88..e7d4817681f2 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -183,7 +183,7 @@ static void bch_btree_init_next(struct btree *b) void bkey_put(struct cache_set *c, struct bkey *k) { - unsigned i; + unsigned int i; for (i = 0; i < KEY_PTRS(k); i++) if (ptr_available(c, k, i)) @@ -287,6 +287,7 @@ err: static void btree_node_read_endio(struct bio *bio) { struct closure *cl = bio->bi_private; + closure_put(cl); } @@ -435,7 +436,10 @@ static void do_btree_node_write(struct btree *b) continue_at(cl, btree_node_write_done, NULL); } else { - /* No problem for multipage bvec since the bio is just allocated */ + /* + * No problem for multipage bvec since the bio is + * just allocated + */ b->bio->bi_vcnt = 0; bch_bio_map(b->bio, i); @@ -479,7 +483,7 @@ void __bch_btree_node_write(struct btree *b, struct closure *parent) void bch_btree_node_write(struct btree *b, struct closure *parent) { - unsigned nsets = b->keys.nsets; + unsigned int nsets = b->keys.nsets; lockdep_assert_held(&b->lock); @@ -581,7 +585,7 @@ static void mca_bucket_free(struct btree *b) list_move(&b->list, &b->c->btree_cache_freeable); } -static unsigned btree_order(struct bkey *k) +static unsigned int btree_order(struct bkey *k) { return ilog2(KEY_SIZE(k) / PAGE_SECTORS ?: 1); } @@ -589,7 +593,7 @@ static unsigned btree_order(struct bkey *k) static void mca_data_alloc(struct btree *b, struct bkey *k, gfp_t gfp) { if (!bch_btree_keys_alloc(&b->keys, - max_t(unsigned, + max_t(unsigned int, ilog2(b->c->btree_pages), btree_order(k)), gfp)) { @@ -604,6 +608,7 @@ static struct btree *mca_bucket_alloc(struct cache_set *c, struct bkey *k, gfp_t gfp) { struct btree *b = kzalloc(sizeof(struct btree), gfp); + if (!b) return NULL; @@ -620,7 +625,7 @@ static struct btree *mca_bucket_alloc(struct cache_set *c, return b; } -static int mca_reap(struct btree *b, unsigned min_order, bool flush) +static int mca_reap(struct btree *b, unsigned int min_order, bool flush) { struct closure cl; @@ -746,6 +751,7 @@ void bch_btree_cache_free(struct cache_set *c) { struct btree *b; struct closure cl; + closure_init_stack(&cl); if (c->shrink.list.next) @@ -786,7 +792,7 @@ void bch_btree_cache_free(struct cache_set *c) int bch_btree_cache_alloc(struct cache_set *c) { - unsigned i; + unsigned int i; for (i = 0; i < mca_reserve(c); i++) if (!mca_bucket_alloc(c, &ZERO_KEY, GFP_KERNEL)) @@ -1124,6 +1130,7 @@ static struct btree *btree_node_alloc_replacement(struct btree *b, struct btree_op *op) { struct btree *n = bch_btree_node_alloc(b->c, op, b->level, b->parent); + if (!IS_ERR_OR_NULL(n)) { mutex_lock(&n->write_lock); bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort); @@ -1136,7 +1143,7 @@ static struct btree *btree_node_alloc_replacement(struct btree *b, static void make_btree_freeing_key(struct btree *b, struct bkey *k) { - unsigned i; + unsigned int i; mutex_lock(&b->c->bucket_lock); @@ -1157,7 +1164,7 @@ static int btree_check_reserve(struct btree *b, struct btree_op *op) { struct cache_set *c = b->c; struct cache *ca; - unsigned i, reserve = (c->root->level - b->level) * 2 + 1; + unsigned int i, reserve = (c->root->level - b->level) * 2 + 1; mutex_lock(&c->bucket_lock); @@ -1181,7 +1188,7 @@ static uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k) { uint8_t stale = 0; - unsigned i; + unsigned int i; struct bucket *g; /* @@ -1219,7 +1226,7 @@ static uint8_t __bch_btree_mark_key(struct cache_set *c, int level, SET_GC_MARK(g, GC_MARK_RECLAIMABLE); /* guard against overflow */ - SET_GC_SECTORS_USED(g, min_t(unsigned, + SET_GC_SECTORS_USED(g, min_t(unsigned int, GC_SECTORS_USED(g) + KEY_SIZE(k), MAX_GC_SECTORS_USED)); @@ -1233,7 +1240,7 @@ static uint8_t __bch_btree_mark_key(struct cache_set *c, int level, void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k) { - unsigned i; + unsigned int i; for (i = 0; i < KEY_PTRS(k); i++) if (ptr_available(c, k, i) && @@ -1259,7 +1266,7 @@ void bch_update_bucket_in_use(struct cache_set *c, struct gc_stat *stats) static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc) { uint8_t stale = 0; - unsigned keys = 0, good_keys = 0; + unsigned int keys = 0, good_keys = 0; struct bkey *k; struct btree_iter iter; struct bset_tree *t; @@ -1302,16 +1309,18 @@ static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc) struct gc_merge_info { struct btree *b; - unsigned keys; + unsigned int keys; }; -static int bch_btree_insert_node(struct btree *, struct btree_op *, - struct keylist *, atomic_t *, struct bkey *); +static int bch_btree_insert_node(struct btree *b, struct btree_op *op, + struct keylist *insert_keys, + atomic_t *journal_ref, + struct bkey *replace_key); static int btree_gc_coalesce(struct btree *b, struct btree_op *op, struct gc_stat *gc, struct gc_merge_info *r) { - unsigned i, nodes = 0, keys = 0, blocks; + unsigned int i, nodes = 0, keys = 0, blocks; struct btree *new_nodes[GC_MERGE_NODES]; struct keylist keylist; struct closure cl; @@ -1511,11 +1520,11 @@ static int btree_gc_rewrite_node(struct btree *b, struct btree_op *op, return -EINTR; } -static unsigned btree_gc_count_keys(struct btree *b) +static unsigned int btree_gc_count_keys(struct btree *b) { struct bkey *k; struct btree_iter iter; - unsigned ret = 0; + unsigned int ret = 0; for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad) ret += bkey_u64s(k); @@ -1678,7 +1687,7 @@ static void btree_gc_start(struct cache_set *c) { struct cache *ca; struct bucket *b; - unsigned i; + unsigned int i; if (!c->gc_mark_valid) return; @@ -1704,7 +1713,7 @@ static void bch_btree_gc_finish(struct cache_set *c) { struct bucket *b; struct cache *ca; - unsigned i; + unsigned int i; mutex_lock(&c->bucket_lock); @@ -1722,7 +1731,7 @@ static void bch_btree_gc_finish(struct cache_set *c) struct bcache_device *d = c->devices[i]; struct cached_dev *dc; struct keybuf_key *w, *n; - unsigned j; + unsigned int j; if (!d || UUID_FLASH_ONLY(&c->uuids[i])) continue; @@ -1814,7 +1823,7 @@ static void bch_btree_gc(struct cache_set *c) static bool gc_should_run(struct cache_set *c) { struct cache *ca; - unsigned i; + unsigned int i; for_each_cache(ca, c, i) if (ca->invalidate_needs_gc) @@ -1905,7 +1914,7 @@ void bch_initial_gc_finish(struct cache_set *c) { struct cache *ca; struct bucket *b; - unsigned i; + unsigned int i; bch_btree_gc_finish(c); @@ -1945,7 +1954,7 @@ void bch_initial_gc_finish(struct cache_set *c) static bool btree_insert_key(struct btree *b, struct bkey *k, struct bkey *replace_key) { - unsigned status; + unsigned int status; BUG_ON(bkey_cmp(k, &b->key) > 0); @@ -2044,7 +2053,7 @@ static int btree_split(struct btree *b, struct btree_op *op, block_bytes(n1->c)) > (btree_blocks(b) * 4) / 5; if (split) { - unsigned keys = 0; + unsigned int keys = 0; trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys); @@ -2222,10 +2231,10 @@ int bch_btree_insert_check_key(struct btree *b, struct btree_op *op, rw_lock(true, b, b->level); if (b->key.ptr[0] != btree_ptr || - b->seq != seq + 1) { + b->seq != seq + 1) { op->lock = b->level; goto out; - } + } } SET_KEY_PTRS(check_key, 1); @@ -2300,7 +2309,7 @@ int bch_btree_insert(struct cache_set *c, struct keylist *keys, void bch_btree_set_root(struct btree *b) { - unsigned i; + unsigned int i; struct closure cl; closure_init_stack(&cl); @@ -2412,7 +2421,7 @@ static inline int keybuf_nonoverlapping_cmp(struct keybuf_key *l, struct refill { struct btree_op op; - unsigned nr_found; + unsigned int nr_found; struct keybuf *buf; struct bkey *end; keybuf_pred_fn *pred; @@ -2488,6 +2497,7 @@ void bch_refill_keybuf(struct cache_set *c, struct keybuf *buf, if (!RB_EMPTY_ROOT(&buf->keys)) { struct keybuf_key *w; + w = RB_FIRST(&buf->keys, struct keybuf_key, node); buf->start = START_KEY(&w->key); @@ -2519,6 +2529,7 @@ bool bch_keybuf_check_overlapping(struct keybuf *buf, struct bkey *start, { bool ret = false; struct keybuf_key *p, *w, s; + s.key = *start; if (bkey_cmp(end, &buf->start) <= 0 || @@ -2545,6 +2556,7 @@ bool bch_keybuf_check_overlapping(struct keybuf *buf, struct bkey *start, struct keybuf_key *bch_keybuf_next(struct keybuf *buf) { struct keybuf_key *w; + spin_lock(&buf->lock); w = RB_FIRST(&buf->keys, struct keybuf_key, node); diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h index 68e9d926134d..a68d6c55783b 100644 --- a/drivers/md/bcache/btree.h +++ b/drivers/md/bcache/btree.h @@ -184,7 +184,7 @@ static inline struct bset *btree_bset_last(struct btree *b) return bset_tree_last(&b->keys)->data; } -static inline unsigned bset_block_offset(struct btree *b, struct bset *i) +static inline unsigned int bset_block_offset(struct btree *b, struct bset *i) { return bset_sector_offset(&b->keys, i) >> b->c->block_bits; } @@ -213,7 +213,7 @@ struct btree_op { /* Btree level at which we start taking write locks */ short lock; - unsigned insert_collision:1; + unsigned int insert_collision:1; }; static inline void bch_btree_op_init(struct btree_op *op, int write_lock_level) @@ -238,26 +238,28 @@ static inline void rw_unlock(bool w, struct btree *b) (w ? up_write : up_read)(&b->lock); } -void bch_btree_node_read_done(struct btree *); -void __bch_btree_node_write(struct btree *, struct closure *); -void bch_btree_node_write(struct btree *, struct closure *); - -void bch_btree_set_root(struct btree *); -struct btree *__bch_btree_node_alloc(struct cache_set *, struct btree_op *, - int, bool, struct btree *); -struct btree *bch_btree_node_get(struct cache_set *, struct btree_op *, - struct bkey *, int, bool, struct btree *); - -int bch_btree_insert_check_key(struct btree *, struct btree_op *, - struct bkey *); -int bch_btree_insert(struct cache_set *, struct keylist *, - atomic_t *, struct bkey *); - -int bch_gc_thread_start(struct cache_set *); -void bch_initial_gc_finish(struct cache_set *); -void bch_moving_gc(struct cache_set *); -int bch_btree_check(struct cache_set *); -void bch_initial_mark_key(struct cache_set *, int, struct bkey *); +void bch_btree_node_read_done(struct btree *b); +void __bch_btree_node_write(struct btree *b, struct closure *parent); +void bch_btree_node_write(struct btree *b, struct closure *parent); + +void bch_btree_set_root(struct btree *b); +struct btree *__bch_btree_node_alloc(struct cache_set *c, struct btree_op *op, + int level, bool wait, + struct btree *parent); +struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op, + struct bkey *k, int level, bool write, + struct btree *parent); + +int bch_btree_insert_check_key(struct btree *b, struct btree_op *op, + struct bkey *check_key); +int bch_btree_insert(struct cache_set *c, struct keylist *keys, + atomic_t *journal_ref, struct bkey *replace_key); + +int bch_gc_thread_start(struct cache_set *c); +void bch_initial_gc_finish(struct cache_set *c); +void bch_moving_gc(struct cache_set *c); +int bch_btree_check(struct cache_set *c); +void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k); static inline void wake_up_gc(struct cache_set *c) { @@ -272,9 +274,9 @@ static inline void wake_up_gc(struct cache_set *c) #define MAP_END_KEY 1 -typedef int (btree_map_nodes_fn)(struct btree_op *, struct btree *); -int __bch_btree_map_nodes(struct btree_op *, struct cache_set *, - struct bkey *, btree_map_nodes_fn *, int); +typedef int (btree_map_nodes_fn)(struct btree_op *b_op, struct btree *b); +int __bch_btree_map_nodes(struct btree_op *op, struct cache_set *c, + struct bkey *from, btree_map_nodes_fn *fn, int flags); static inline int bch_btree_map_nodes(struct btree_op *op, struct cache_set *c, struct bkey *from, btree_map_nodes_fn *fn) @@ -290,21 +292,23 @@ static inline int bch_btree_map_leaf_nodes(struct btree_op *op, return __bch_btree_map_nodes(op, c, from, fn, MAP_LEAF_NODES); } -typedef int (btree_map_keys_fn)(struct btree_op *, struct btree *, - struct bkey *); -int bch_btree_map_keys(struct btree_op *, struct cache_set *, - struct bkey *, btree_map_keys_fn *, int); - -typedef bool (keybuf_pred_fn)(struct keybuf *, struct bkey *); - -void bch_keybuf_init(struct keybuf *); -void bch_refill_keybuf(struct cache_set *, struct keybuf *, - struct bkey *, keybuf_pred_fn *); -bool bch_keybuf_check_overlapping(struct keybuf *, struct bkey *, - struct bkey *); -void bch_keybuf_del(struct keybuf *, struct keybuf_key *); -struct keybuf_key *bch_keybuf_next(struct keybuf *); -struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *, struct keybuf *, - struct bkey *, keybuf_pred_fn *); +typedef int (btree_map_keys_fn)(struct btree_op *op, struct btree *b, + struct bkey *k); +int bch_btree_map_keys(struct btree_op *op, struct cache_set *c, + struct bkey *from, btree_map_keys_fn *fn, int flags); + +typedef bool (keybuf_pred_fn)(struct keybuf *buf, struct bkey *k); + +void bch_keybuf_init(struct keybuf *buf); +void bch_refill_keybuf(struct cache_set *c, struct keybuf *buf, + struct bkey *end, keybuf_pred_fn *pred); +bool bch_keybuf_check_overlapping(struct keybuf *buf, struct bkey *start, + struct bkey *end); +void bch_keybuf_del(struct keybuf *buf, struct keybuf_key *w); +struct keybuf_key *bch_keybuf_next(struct keybuf *buf); +struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *c, + struct keybuf *buf, + struct bkey *end, + keybuf_pred_fn *pred); void bch_update_bucket_in_use(struct cache_set *c, struct gc_stat *stats); #endif diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c index 618253683d40..73f5319295bc 100644 --- a/drivers/md/bcache/closure.c +++ b/drivers/md/bcache/closure.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Asynchronous refcounty things * @@ -162,12 +163,13 @@ static struct dentry *closure_debug; static int debug_seq_show(struct seq_file *f, void *data) { struct closure *cl; + spin_lock_irq(&closure_list_lock); list_for_each_entry(cl, &closure_list, all) { int r = atomic_read(&cl->remaining); - seq_printf(f, "%p: %pF -> %pf p %p r %i ", + seq_printf(f, "%p: %pS -> %pS p %p r %i ", cl, (void *) cl->ip, cl->fn, cl->parent, r & CLOSURE_REMAINING_MASK); @@ -177,7 +179,7 @@ static int debug_seq_show(struct seq_file *f, void *data) r & CLOSURE_RUNNING ? "R" : ""); if (r & CLOSURE_WAITING) - seq_printf(f, " W %pF\n", + seq_printf(f, " W %pS\n", (void *) cl->waiting_on); seq_printf(f, "\n"); diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h index 7c2c5bc7c88b..eca0d496b686 100644 --- a/drivers/md/bcache/closure.h +++ b/drivers/md/bcache/closure.h @@ -159,7 +159,7 @@ struct closure { #define CLOSURE_MAGIC_DEAD 0xc054dead #define CLOSURE_MAGIC_ALIVE 0xc054a11e - unsigned magic; + unsigned int magic; struct list_head all; unsigned long ip; unsigned long waiting_on; @@ -289,10 +289,12 @@ static inline void closure_init_stack(struct closure *cl) } /** - * closure_wake_up - wake up all closures on a wait list. + * closure_wake_up - wake up all closures on a wait list, + * with memory barrier */ static inline void closure_wake_up(struct closure_waitlist *list) { + /* Memory barrier for the wait list */ smp_mb(); __closure_wake_up(list); } diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 12034c07257b..06da66b2488a 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -67,34 +67,35 @@ void bch_btree_verify(struct btree *b) if (inmemory->keys != sorted->keys || memcmp(inmemory->start, sorted->start, - (void *) bset_bkey_last(inmemory) - (void *) inmemory->start)) { + (void *) bset_bkey_last(inmemory) - + (void *) inmemory->start)) { struct bset *i; - unsigned j; + unsigned int j; console_lock(); - printk(KERN_ERR "*** in memory:\n"); + pr_err("*** in memory:\n"); bch_dump_bset(&b->keys, inmemory, 0); - printk(KERN_ERR "*** read back in:\n"); + pr_err("*** read back in:\n"); bch_dump_bset(&v->keys, sorted, 0); for_each_written_bset(b, ondisk, i) { - unsigned block = ((void *) i - (void *) ondisk) / + unsigned int block = ((void *) i - (void *) ondisk) / block_bytes(b->c); - printk(KERN_ERR "*** on disk block %u:\n", block); + pr_err("*** on disk block %u:\n", block); bch_dump_bset(&b->keys, i, block); } - printk(KERN_ERR "*** block %zu not written\n", + pr_err("*** block %zu not written\n", ((void *) i - (void *) ondisk) / block_bytes(b->c)); for (j = 0; j < inmemory->keys; j++) if (inmemory->d[j] != sorted->d[j]) break; - printk(KERN_ERR "b->written %u\n", b->written); + pr_err("b->written %u\n", b->written); console_unlock(); panic("verify failed at %u\n", j); @@ -176,9 +177,9 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf, while (size) { struct keybuf_key *w; - unsigned bytes = min(i->bytes, size); - + unsigned int bytes = min(i->bytes, size); int err = copy_to_user(buf, i->buf, bytes); + if (err) return err; @@ -237,8 +238,8 @@ void bch_debug_init_cache_set(struct cache_set *c) { if (!IS_ERR_OR_NULL(bcache_debug)) { char name[50]; - snprintf(name, 50, "bcache-%pU", c->sb.set_uuid); + snprintf(name, 50, "bcache-%pU", c->sb.set_uuid); c->debug = debugfs_create_file(name, 0400, bcache_debug, c, &cache_set_debug_ops); } diff --git a/drivers/md/bcache/debug.h b/drivers/md/bcache/debug.h index acc48d3fa274..fb3d4dff4b26 100644 --- a/drivers/md/bcache/debug.h +++ b/drivers/md/bcache/debug.h @@ -8,8 +8,8 @@ struct cache_set; #ifdef CONFIG_BCACHE_DEBUG -void bch_btree_verify(struct btree *); -void bch_data_verify(struct cached_dev *, struct bio *); +void bch_btree_verify(struct btree *b); +void bch_data_verify(struct cached_dev *dc, struct bio *bio); #define expensive_debug_checks(c) ((c)->expensive_debug_checks) #define key_merging_disabled(c) ((c)->key_merging_disabled) @@ -27,7 +27,7 @@ static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {} #endif #ifdef CONFIG_DEBUG_FS -void bch_debug_init_cache_set(struct cache_set *); +void bch_debug_init_cache_set(struct cache_set *c); #else static inline void bch_debug_init_cache_set(struct cache_set *c) {} #endif diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index 1d096742eb41..c809724e6571 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c @@ -46,7 +46,7 @@ static bool bch_key_sort_cmp(struct btree_iter_set l, static bool __ptr_invalid(struct cache_set *c, const struct bkey *k) { - unsigned i; + unsigned int i; for (i = 0; i < KEY_PTRS(k); i++) if (ptr_available(c, k, i)) { @@ -67,7 +67,7 @@ static bool __ptr_invalid(struct cache_set *c, const struct bkey *k) static const char *bch_ptr_status(struct cache_set *c, const struct bkey *k) { - unsigned i; + unsigned int i; for (i = 0; i < KEY_PTRS(k); i++) if (ptr_available(c, k, i)) { @@ -96,7 +96,7 @@ static const char *bch_ptr_status(struct cache_set *c, const struct bkey *k) void bch_extent_to_text(char *buf, size_t size, const struct bkey *k) { - unsigned i = 0; + unsigned int i = 0; char *out = buf, *end = buf + size; #define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) @@ -126,22 +126,22 @@ void bch_extent_to_text(char *buf, size_t size, const struct bkey *k) static void bch_bkey_dump(struct btree_keys *keys, const struct bkey *k) { struct btree *b = container_of(keys, struct btree, keys); - unsigned j; + unsigned int j; char buf[80]; bch_extent_to_text(buf, sizeof(buf), k); - printk(" %s", buf); + pr_err(" %s", buf); for (j = 0; j < KEY_PTRS(k); j++) { size_t n = PTR_BUCKET_NR(b->c, k, j); - printk(" bucket %zu", n); + pr_err(" bucket %zu", n); if (n >= b->c->sb.first_bucket && n < b->c->sb.nbuckets) - printk(" prio %i", + pr_err(" prio %i", PTR_BUCKET(b->c, k, j)->prio); } - printk(" %s\n", bch_ptr_status(b->c, k)); + pr_err(" %s\n", bch_ptr_status(b->c, k)); } /* Btree ptrs */ @@ -166,12 +166,13 @@ bad: static bool bch_btree_ptr_invalid(struct btree_keys *bk, const struct bkey *k) { struct btree *b = container_of(bk, struct btree, keys); + return __bch_btree_ptr_invalid(b->c, k); } static bool btree_ptr_bad_expensive(struct btree *b, const struct bkey *k) { - unsigned i; + unsigned int i; char buf[80]; struct bucket *g; @@ -204,7 +205,7 @@ err: static bool bch_btree_ptr_bad(struct btree_keys *bk, const struct bkey *k) { struct btree *b = container_of(bk, struct btree, keys); - unsigned i; + unsigned int i; if (!bkey_cmp(k, &ZERO_KEY) || !KEY_PTRS(k) || @@ -327,13 +328,14 @@ static bool bch_extent_insert_fixup(struct btree_keys *b, struct cache_set *c = container_of(b, struct btree, keys)->c; uint64_t old_offset; - unsigned old_size, sectors_found = 0; + unsigned int old_size, sectors_found = 0; BUG_ON(!KEY_OFFSET(insert)); BUG_ON(!KEY_SIZE(insert)); while (1) { struct bkey *k = bch_btree_iter_next(iter); + if (!k) break; @@ -363,7 +365,7 @@ static bool bch_extent_insert_fixup(struct btree_keys *b, * k might have been split since we inserted/found the * key we're replacing */ - unsigned i; + unsigned int i; uint64_t offset = KEY_START(k) - KEY_START(replace_key); @@ -498,11 +500,12 @@ bad: static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k) { struct btree *b = container_of(bk, struct btree, keys); + return __bch_extent_invalid(b->c, k); } static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k, - unsigned ptr) + unsigned int ptr) { struct bucket *g = PTR_BUCKET(b->c, k, ptr); char buf[80]; @@ -534,7 +537,7 @@ err: static bool bch_extent_bad(struct btree_keys *bk, const struct bkey *k) { struct btree *b = container_of(bk, struct btree, keys); - unsigned i, stale; + unsigned int i, stale; if (!KEY_PTRS(k) || bch_extent_invalid(bk, k)) @@ -574,10 +577,12 @@ static uint64_t merge_chksums(struct bkey *l, struct bkey *r) ~((uint64_t)1 << 63); } -static bool bch_extent_merge(struct btree_keys *bk, struct bkey *l, struct bkey *r) +static bool bch_extent_merge(struct btree_keys *bk, + struct bkey *l, + struct bkey *r) { struct btree *b = container_of(bk, struct btree, keys); - unsigned i; + unsigned int i; if (key_merging_disabled(b->c)) return false; diff --git a/drivers/md/bcache/extents.h b/drivers/md/bcache/extents.h index 0cd3575afa1d..4d667e05bb73 100644 --- a/drivers/md/bcache/extents.h +++ b/drivers/md/bcache/extents.h @@ -8,8 +8,8 @@ extern const struct btree_keys_ops bch_extent_keys_ops; struct bkey; struct cache_set; -void bch_extent_to_text(char *, size_t, const struct bkey *); -bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *); -bool __bch_extent_invalid(struct cache_set *, const struct bkey *); +void bch_extent_to_text(char *buf, size_t size, const struct bkey *k); +bool __bch_btree_ptr_invalid(struct cache_set *c, const struct bkey *k); +bool __bch_extent_invalid(struct cache_set *c, const struct bkey *k); #endif /* _BCACHE_EXTENTS_H */ diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 9612873afee2..c25097968319 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -17,6 +17,7 @@ void bch_bbio_free(struct bio *bio, struct cache_set *c) { struct bbio *b = container_of(bio, struct bbio, bio); + mempool_free(b, &c->bio_meta); } @@ -42,9 +43,10 @@ void __bch_submit_bbio(struct bio *bio, struct cache_set *c) } void bch_submit_bbio(struct bio *bio, struct cache_set *c, - struct bkey *k, unsigned ptr) + struct bkey *k, unsigned int ptr) { struct bbio *b = container_of(bio, struct bbio, bio); + bch_bkey_copy_single_ptr(&b->key, k, ptr); __bch_submit_bbio(bio, c); } @@ -52,7 +54,7 @@ void bch_submit_bbio(struct bio *bio, struct cache_set *c, /* IO errors */ void bch_count_backing_io_errors(struct cached_dev *dc, struct bio *bio) { - unsigned errors; + unsigned int errors; WARN_ONCE(!dc, "NULL pointer of struct cached_dev"); @@ -75,16 +77,16 @@ void bch_count_io_errors(struct cache *ca, */ if (ca->set->error_decay) { - unsigned count = atomic_inc_return(&ca->io_count); + unsigned int count = atomic_inc_return(&ca->io_count); while (count > ca->set->error_decay) { - unsigned errors; - unsigned old = count; - unsigned new = count - ca->set->error_decay; + unsigned int errors; + unsigned int old = count; + unsigned int new = count - ca->set->error_decay; /* * First we subtract refresh from count; each time we - * succesfully do so, we rescale the errors once: + * successfully do so, we rescale the errors once: */ count = atomic_cmpxchg(&ca->io_count, old, new); @@ -104,7 +106,7 @@ void bch_count_io_errors(struct cache *ca, } if (error) { - unsigned errors = atomic_add_return(1 << IO_ERROR_SHIFT, + unsigned int errors = atomic_add_return(1 << IO_ERROR_SHIFT, &ca->io_errors); errors >>= IO_ERROR_SHIFT; @@ -126,18 +128,18 @@ void bch_bbio_count_io_errors(struct cache_set *c, struct bio *bio, struct cache *ca = PTR_CACHE(c, &b->key, 0); int is_read = (bio_data_dir(bio) == READ ? 1 : 0); - unsigned threshold = op_is_write(bio_op(bio)) + unsigned int threshold = op_is_write(bio_op(bio)) ? c->congested_write_threshold_us : c->congested_read_threshold_us; if (threshold) { - unsigned t = local_clock_us(); - + unsigned int t = local_clock_us(); int us = t - b->submit_time_us; int congested = atomic_read(&c->congested); if (us > (int) threshold) { int ms = us / 1024; + c->congested_last_us = t; ms = min(ms, CONGESTED_MAX + congested); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index 10748c626a1d..6116bbf870d8 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -28,11 +28,12 @@ static void journal_read_endio(struct bio *bio) { struct closure *cl = bio->bi_private; + closure_put(cl); } static int journal_read_bucket(struct cache *ca, struct list_head *list, - unsigned bucket_index) + unsigned int bucket_index) { struct journal_device *ja = &ca->journal; struct bio *bio = &ja->bio; @@ -40,7 +41,7 @@ static int journal_read_bucket(struct cache *ca, struct list_head *list, struct journal_replay *i; struct jset *j, *data = ca->set->journal.w[0].data; struct closure cl; - unsigned len, left, offset = 0; + unsigned int len, left, offset = 0; int ret = 0; sector_t bucket = bucket_to_sector(ca->set, ca->sb.d[bucket_index]); @@ -50,7 +51,7 @@ static int journal_read_bucket(struct cache *ca, struct list_head *list, while (offset < ca->sb.bucket_size) { reread: left = ca->sb.bucket_size - offset; - len = min_t(unsigned, left, PAGE_SECTORS << JSET_BITS); + len = min_t(unsigned int, left, PAGE_SECTORS << JSET_BITS); bio_reset(bio); bio->bi_iter.bi_sector = bucket + offset; @@ -154,12 +155,12 @@ int bch_journal_read(struct cache_set *c, struct list_head *list) }) struct cache *ca; - unsigned iter; + unsigned int iter; for_each_cache(ca, c, iter) { struct journal_device *ja = &ca->journal; DECLARE_BITMAP(bitmap, SB_JOURNAL_BUCKETS); - unsigned i, l, r, m; + unsigned int i, l, r, m; uint64_t seq; bitmap_zero(bitmap, SB_JOURNAL_BUCKETS); @@ -192,7 +193,8 @@ int bch_journal_read(struct cache_set *c, struct list_head *list) for (l = find_first_zero_bit(bitmap, ca->sb.njournal_buckets); l < ca->sb.njournal_buckets; - l = find_next_zero_bit(bitmap, ca->sb.njournal_buckets, l + 1)) + l = find_next_zero_bit(bitmap, ca->sb.njournal_buckets, + l + 1)) if (read_bucket(l)) goto bsearch; @@ -304,7 +306,7 @@ void bch_journal_mark(struct cache_set *c, struct list_head *list) k < bset_bkey_last(&i->j); k = bkey_next(k)) if (!__bch_extent_invalid(c, k)) { - unsigned j; + unsigned int j; for (j = 0; j < KEY_PTRS(k); j++) if (ptr_available(c, k, j)) @@ -492,7 +494,7 @@ static void journal_reclaim(struct cache_set *c) struct bkey *k = &c->journal.key; struct cache *ca; uint64_t last_seq; - unsigned iter, n = 0; + unsigned int iter, n = 0; atomic_t p __maybe_unused; atomic_long_inc(&c->reclaim); @@ -526,7 +528,7 @@ static void journal_reclaim(struct cache_set *c) for_each_cache(ca, c, iter) { struct journal_device *ja = &ca->journal; - unsigned next = (ja->cur_idx + 1) % ca->sb.njournal_buckets; + unsigned int next = (ja->cur_idx + 1) % ca->sb.njournal_buckets; /* No space available on this device */ if (next == ja->discard_idx) @@ -580,7 +582,7 @@ static void journal_write_endio(struct bio *bio) closure_put(&w->c->journal.io); } -static void journal_write(struct closure *); +static void journal_write(struct closure *cl); static void journal_write_done(struct closure *cl) { @@ -609,11 +611,12 @@ static void journal_write_unlocked(struct closure *cl) struct cache *ca; struct journal_write *w = c->journal.cur; struct bkey *k = &c->journal.key; - unsigned i, sectors = set_blocks(w->data, block_bytes(c)) * + unsigned int i, sectors = set_blocks(w->data, block_bytes(c)) * c->sb.block_size; struct bio *bio; struct bio_list list; + bio_list_init(&list); if (!w->need_write) { @@ -705,7 +708,7 @@ static void journal_try_write(struct cache_set *c) } static struct journal_write *journal_wait_for_write(struct cache_set *c, - unsigned nkeys) + unsigned int nkeys) __acquires(&c->journal.lock) { size_t sectors; diff --git a/drivers/md/bcache/journal.h b/drivers/md/bcache/journal.h index b5788199188f..66f0facff84b 100644 --- a/drivers/md/bcache/journal.h +++ b/drivers/md/bcache/journal.h @@ -110,7 +110,7 @@ struct journal { struct delayed_work work; /* Number of blocks free in the bucket(s) we're currently writing to */ - unsigned blocks_free; + unsigned int blocks_free; uint64_t seq; DECLARE_FIFO(atomic_t, pin); @@ -131,13 +131,13 @@ struct journal_device { uint64_t seq[SB_JOURNAL_BUCKETS]; /* Journal bucket we're currently writing to */ - unsigned cur_idx; + unsigned int cur_idx; /* Last journal bucket that still contains an open journal entry */ - unsigned last_idx; + unsigned int last_idx; /* Next journal bucket to be discarded */ - unsigned discard_idx; + unsigned int discard_idx; #define DISCARD_READY 0 #define DISCARD_IN_FLIGHT 1 @@ -167,14 +167,16 @@ struct cache_set; struct btree_op; struct keylist; -atomic_t *bch_journal(struct cache_set *, struct keylist *, struct closure *); -void bch_journal_next(struct journal *); -void bch_journal_mark(struct cache_set *, struct list_head *); -void bch_journal_meta(struct cache_set *, struct closure *); -int bch_journal_read(struct cache_set *, struct list_head *); -int bch_journal_replay(struct cache_set *, struct list_head *); - -void bch_journal_free(struct cache_set *); -int bch_journal_alloc(struct cache_set *); +atomic_t *bch_journal(struct cache_set *c, + struct keylist *keys, + struct closure *parent); +void bch_journal_next(struct journal *j); +void bch_journal_mark(struct cache_set *c, struct list_head *list); +void bch_journal_meta(struct cache_set *c, struct closure *cl); +int bch_journal_read(struct cache_set *c, struct list_head *list); +int bch_journal_replay(struct cache_set *c, struct list_head *list); + +void bch_journal_free(struct cache_set *c); +int bch_journal_alloc(struct cache_set *c); #endif /* _BCACHE_JOURNAL_H */ diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c index a24c3a95b2c0..7891fb512736 100644 --- a/drivers/md/bcache/movinggc.c +++ b/drivers/md/bcache/movinggc.c @@ -23,7 +23,7 @@ static bool moving_pred(struct keybuf *buf, struct bkey *k) { struct cache_set *c = container_of(buf, struct cache_set, moving_gc_keys); - unsigned i; + unsigned int i; for (i = 0; i < KEY_PTRS(k); i++) if (ptr_available(c, k, i) && @@ -38,6 +38,7 @@ static bool moving_pred(struct keybuf *buf, struct bkey *k) static void moving_io_destructor(struct closure *cl) { struct moving_io *io = container_of(cl, struct moving_io, cl); + kfree(io); } @@ -186,9 +187,10 @@ static bool bucket_cmp(struct bucket *l, struct bucket *r) return GC_SECTORS_USED(l) < GC_SECTORS_USED(r); } -static unsigned bucket_heap_top(struct cache *ca) +static unsigned int bucket_heap_top(struct cache *ca) { struct bucket *b; + return (b = heap_peek(&ca->heap)) ? GC_SECTORS_USED(b) : 0; } @@ -196,7 +198,7 @@ void bch_moving_gc(struct cache_set *c) { struct cache *ca; struct bucket *b; - unsigned i; + unsigned int i; if (!c->copy_gc_enabled) return; @@ -204,9 +206,9 @@ void bch_moving_gc(struct cache_set *c) mutex_lock(&c->bucket_lock); for_each_cache(ca, c, i) { - unsigned sectors_to_move = 0; - unsigned reserve_sectors = ca->sb.bucket_size * - fifo_used(&ca->free[RESERVE_MOVINGGC]); + unsigned int sectors_to_move = 0; + unsigned int reserve_sectors = ca->sb.bucket_size * + fifo_used(&ca->free[RESERVE_MOVINGGC]); ca->heap.used = 0; diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 7dbe8b6316a0..51be355a3309 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -25,9 +25,9 @@ struct kmem_cache *bch_search_cache; -static void bch_data_insert_start(struct closure *); +static void bch_data_insert_start(struct closure *cl); -static unsigned cache_mode(struct cached_dev *dc) +static unsigned int cache_mode(struct cached_dev *dc) { return BDEV_CACHE_MODE(&dc->sb); } @@ -45,6 +45,7 @@ static void bio_csum(struct bio *bio, struct bkey *k) bio_for_each_segment(bv, bio, iter) { void *d = kmap(bv.bv_page) + bv.bv_offset; + csum = bch_crc64_update(csum, d, bv.bv_len); kunmap(bv.bv_page); } @@ -98,7 +99,7 @@ static void bch_data_insert_keys(struct closure *cl) closure_return(cl); } -static int bch_keylist_realloc(struct keylist *l, unsigned u64s, +static int bch_keylist_realloc(struct keylist *l, unsigned int u64s, struct cache_set *c) { size_t oldsize = bch_keylist_nkeys(l); @@ -125,7 +126,7 @@ static void bch_data_invalidate(struct closure *cl) bio_sectors(bio), (uint64_t) bio->bi_iter.bi_sector); while (bio_sectors(bio)) { - unsigned sectors = min(bio_sectors(bio), + unsigned int sectors = min(bio_sectors(bio), 1U << (KEY_SIZE_BITS - 1)); if (bch_keylist_realloc(&op->insert_keys, 2, op->c)) @@ -135,7 +136,9 @@ static void bch_data_invalidate(struct closure *cl) bio->bi_iter.bi_size -= sectors << 9; bch_keylist_add(&op->insert_keys, - &KEY(op->inode, bio->bi_iter.bi_sector, sectors)); + &KEY(op->inode, + bio->bi_iter.bi_sector, + sectors)); } op->insert_data_done = true; @@ -151,7 +154,7 @@ static void bch_data_insert_error(struct closure *cl) /* * Our data write just errored, which means we've got a bunch of keys to - * insert that point to data that wasn't succesfully written. + * insert that point to data that wasn't successfully written. * * We don't have to insert those keys but we still have to invalidate * that region of the cache - so, if we just strip off all the pointers @@ -211,7 +214,7 @@ static void bch_data_insert_start(struct closure *cl) bio->bi_opf &= ~(REQ_PREFLUSH|REQ_FUA); do { - unsigned i; + unsigned int i; struct bkey *k; struct bio_set *split = &op->c->bio_split; @@ -328,7 +331,7 @@ void bch_data_insert(struct closure *cl) /* Congested? */ -unsigned bch_get_congested(struct cache_set *c) +unsigned int bch_get_congested(struct cache_set *c) { int i; long rand; @@ -372,8 +375,8 @@ static struct hlist_head *iohash(struct cached_dev *dc, uint64_t k) static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) { struct cache_set *c = dc->disk.c; - unsigned mode = cache_mode(dc); - unsigned sectors, congested = bch_get_congested(c); + unsigned int mode = cache_mode(dc); + unsigned int sectors, congested = bch_get_congested(c); struct task_struct *task = current; struct io *i; @@ -469,11 +472,11 @@ struct search { struct bio *cache_miss; struct bcache_device *d; - unsigned insert_bio_sectors; - unsigned recoverable:1; - unsigned write:1; - unsigned read_dirty_data:1; - unsigned cache_missed:1; + unsigned int insert_bio_sectors; + unsigned int recoverable:1; + unsigned int write:1; + unsigned int read_dirty_data:1; + unsigned int cache_missed:1; unsigned long start_time; @@ -514,20 +517,20 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) struct search *s = container_of(op, struct search, op); struct bio *n, *bio = &s->bio.bio; struct bkey *bio_key; - unsigned ptr; + unsigned int ptr; if (bkey_cmp(k, &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0)) <= 0) return MAP_CONTINUE; if (KEY_INODE(k) != s->iop.inode || KEY_START(k) > bio->bi_iter.bi_sector) { - unsigned bio_sectors = bio_sectors(bio); - unsigned sectors = KEY_INODE(k) == s->iop.inode + unsigned int bio_sectors = bio_sectors(bio); + unsigned int sectors = KEY_INODE(k) == s->iop.inode ? min_t(uint64_t, INT_MAX, KEY_START(k) - bio->bi_iter.bi_sector) : INT_MAX; - int ret = s->d->cache_miss(b, s, bio, sectors); + if (ret != MAP_CONTINUE) return ret; @@ -623,6 +626,7 @@ static void request_endio(struct bio *bio) if (bio->bi_status) { struct search *s = container_of(cl, struct search, cl); + s->iop.status = bio->bi_status; /* Only cache read errors are recoverable */ s->recoverable = false; @@ -813,7 +817,8 @@ static void cached_dev_read_done(struct closure *cl) if (s->iop.bio) { bio_reset(s->iop.bio); - s->iop.bio->bi_iter.bi_sector = s->cache_miss->bi_iter.bi_sector; + s->iop.bio->bi_iter.bi_sector = + s->cache_miss->bi_iter.bi_sector; bio_copy_dev(s->iop.bio, s->cache_miss); s->iop.bio->bi_iter.bi_size = s->insert_bio_sectors << 9; bch_bio_map(s->iop.bio, NULL); @@ -856,10 +861,10 @@ static void cached_dev_read_done_bh(struct closure *cl) } static int cached_dev_cache_miss(struct btree *b, struct search *s, - struct bio *bio, unsigned sectors) + struct bio *bio, unsigned int sectors) { int ret = MAP_CONTINUE; - unsigned reada = 0; + unsigned int reada = 0; struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); struct bio *miss, *cache_bio; @@ -1212,6 +1217,7 @@ static int cached_dev_ioctl(struct bcache_device *d, fmode_t mode, unsigned int cmd, unsigned long arg) { struct cached_dev *dc = container_of(d, struct cached_dev, disk); + return __blkdev_driver_ioctl(dc->bdev, mode, cmd, arg); } @@ -1226,7 +1232,7 @@ static int cached_dev_congested(void *data, int bits) return 1; if (cached_dev_get(dc)) { - unsigned i; + unsigned int i; struct cache *ca; for_each_cache(ca, d->c, i) { @@ -1253,9 +1259,9 @@ void bch_cached_dev_request_init(struct cached_dev *dc) /* Flash backed devices */ static int flash_dev_cache_miss(struct btree *b, struct search *s, - struct bio *bio, unsigned sectors) + struct bio *bio, unsigned int sectors) { - unsigned bytes = min(sectors, bio_sectors(bio)) << 9; + unsigned int bytes = min(sectors, bio_sectors(bio)) << 9; swap(bio->bi_iter.bi_size, bytes); zero_fill_bio(bio); @@ -1338,7 +1344,7 @@ static int flash_dev_congested(void *data, int bits) struct bcache_device *d = data; struct request_queue *q; struct cache *ca; - unsigned i; + unsigned int i; int ret = 0; for_each_cache(ca, d->c, i) { @@ -1361,8 +1367,7 @@ void bch_flash_dev_request_init(struct bcache_device *d) void bch_request_exit(void) { - if (bch_search_cache) - kmem_cache_destroy(bch_search_cache); + kmem_cache_destroy(bch_search_cache); } int __init bch_request_init(void) diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h index dea0886b81c1..aa055cfeb099 100644 --- a/drivers/md/bcache/request.h +++ b/drivers/md/bcache/request.h @@ -8,7 +8,7 @@ struct data_insert_op { struct bio *bio; struct workqueue_struct *wq; - unsigned inode; + unsigned int inode; uint16_t write_point; uint16_t write_prio; blk_status_t status; @@ -17,15 +17,15 @@ struct data_insert_op { uint16_t flags; struct { - unsigned bypass:1; - unsigned writeback:1; - unsigned flush_journal:1; - unsigned csum:1; + unsigned int bypass:1; + unsigned int writeback:1; + unsigned int flush_journal:1; + unsigned int csum:1; - unsigned replace:1; - unsigned replace_collision:1; + unsigned int replace:1; + unsigned int replace_collision:1; - unsigned insert_data_done:1; + unsigned int insert_data_done:1; }; }; @@ -33,7 +33,7 @@ struct data_insert_op { BKEY_PADDED(replace_key); }; -unsigned bch_get_congested(struct cache_set *); +unsigned int bch_get_congested(struct cache_set *c); void bch_data_insert(struct closure *cl); void bch_cached_dev_request_init(struct cached_dev *dc); diff --git a/drivers/md/bcache/stats.c b/drivers/md/bcache/stats.c index be119326297b..894410f3f829 100644 --- a/drivers/md/bcache/stats.c +++ b/drivers/md/bcache/stats.c @@ -33,11 +33,11 @@ * stored left shifted by 16, and scaled back in the sysfs show() function. */ -static const unsigned DAY_RESCALE = 288; -static const unsigned HOUR_RESCALE = 12; -static const unsigned FIVE_MINUTE_RESCALE = 1; -static const unsigned accounting_delay = (HZ * 300) / 22; -static const unsigned accounting_weight = 32; +static const unsigned int DAY_RESCALE = 288; +static const unsigned int HOUR_RESCALE = 12; +static const unsigned int FIVE_MINUTE_RESCALE = 1; +static const unsigned int accounting_delay = (HZ * 300) / 22; +static const unsigned int accounting_weight = 32; /* sysfs reading/writing */ @@ -152,7 +152,7 @@ static void scale_accounting(struct timer_list *t) struct cache_accounting *acc = from_timer(acc, t, timer); #define move_stat(name) do { \ - unsigned t = atomic_xchg(&acc->collector.name, 0); \ + unsigned int t = atomic_xchg(&acc->collector.name, 0); \ t <<= 16; \ acc->five_minute.name += t; \ acc->hour.name += t; \ @@ -200,6 +200,7 @@ void bch_mark_cache_accounting(struct cache_set *c, struct bcache_device *d, bool hit, bool bypass) { struct cached_dev *dc = container_of(d, struct cached_dev, disk); + mark_cache_stats(&dc->accounting.collector, hit, bypass); mark_cache_stats(&c->accounting.collector, hit, bypass); } @@ -207,6 +208,7 @@ void bch_mark_cache_accounting(struct cache_set *c, struct bcache_device *d, void bch_mark_cache_readahead(struct cache_set *c, struct bcache_device *d) { struct cached_dev *dc = container_of(d, struct cached_dev, disk); + atomic_inc(&dc->accounting.collector.cache_readaheads); atomic_inc(&c->accounting.collector.cache_readaheads); } @@ -214,6 +216,7 @@ void bch_mark_cache_readahead(struct cache_set *c, struct bcache_device *d) void bch_mark_cache_miss_collision(struct cache_set *c, struct bcache_device *d) { struct cached_dev *dc = container_of(d, struct cached_dev, disk); + atomic_inc(&dc->accounting.collector.cache_miss_collisions); atomic_inc(&c->accounting.collector.cache_miss_collisions); } diff --git a/drivers/md/bcache/stats.h b/drivers/md/bcache/stats.h index 0b70f9de0c03..abfaabf7e7fc 100644 --- a/drivers/md/bcache/stats.h +++ b/drivers/md/bcache/stats.h @@ -23,7 +23,7 @@ struct cache_stats { unsigned long cache_miss_collisions; unsigned long sectors_bypassed; - unsigned rescale; + unsigned int rescale; }; struct cache_accounting { @@ -53,10 +53,13 @@ void bch_cache_accounting_clear(struct cache_accounting *acc); void bch_cache_accounting_destroy(struct cache_accounting *acc); -void bch_mark_cache_accounting(struct cache_set *, struct bcache_device *, - bool, bool); -void bch_mark_cache_readahead(struct cache_set *, struct bcache_device *); -void bch_mark_cache_miss_collision(struct cache_set *, struct bcache_device *); -void bch_mark_sectors_bypassed(struct cache_set *, struct cached_dev *, int); +void bch_mark_cache_accounting(struct cache_set *c, struct bcache_device *d, + bool hit, bool bypass); +void bch_mark_cache_readahead(struct cache_set *c, struct bcache_device *d); +void bch_mark_cache_miss_collision(struct cache_set *c, + struct bcache_device *d); +void bch_mark_sectors_bypassed(struct cache_set *c, + struct cached_dev *dc, + int sectors); #endif /* _BCACHE_STATS_H_ */ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 55a37641aa95..94c756c66bd7 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * bcache setup/teardown code, and some metadata io - read a superblock and * figure out what to do with it. @@ -61,7 +62,7 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, const char *err; struct cache_sb *s; struct buffer_head *bh = __bread(bdev, 1, SB_SIZE); - unsigned i; + unsigned int i; if (!bh) return "IO error"; @@ -149,7 +150,8 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, goto err; err = "Invalid superblock: device too small"; - if (get_capacity(bdev->bd_disk) < sb->bucket_size * sb->nbuckets) + if (get_capacity(bdev->bd_disk) < + sb->bucket_size * sb->nbuckets) goto err; err = "Bad UUID"; @@ -202,7 +204,7 @@ static void write_bdev_super_endio(struct bio *bio) static void __write_super(struct cache_sb *sb, struct bio *bio) { struct cache_sb *out = page_address(bio_first_page_all(bio)); - unsigned i; + unsigned int i; bio->bi_iter.bi_sector = SB_SECTOR; bio->bi_iter.bi_size = SB_SIZE; @@ -282,7 +284,7 @@ void bcache_write_super(struct cache_set *c) { struct closure *cl = &c->sb_write; struct cache *ca; - unsigned i; + unsigned int i; down(&c->sb_write_mutex); closure_init(cl, &c->cl); @@ -334,7 +336,7 @@ static void uuid_io(struct cache_set *c, int op, unsigned long op_flags, { struct closure *cl = &c->uuid_write; struct uuid_entry *u; - unsigned i; + unsigned int i; char buf[80]; BUG_ON(!parent); @@ -415,8 +417,8 @@ static int __uuid_write(struct cache_set *c) { BKEY_PADDED(key) k; struct closure cl; - closure_init_stack(&cl); + closure_init_stack(&cl); lockdep_assert_held(&bch_register_lock); if (bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, true)) @@ -456,6 +458,7 @@ static struct uuid_entry *uuid_find(struct cache_set *c, const char *uuid) static struct uuid_entry *uuid_find_empty(struct cache_set *c) { static const char zero_uuid[16] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + return uuid_find(c, zero_uuid); } @@ -463,8 +466,8 @@ static struct uuid_entry *uuid_find_empty(struct cache_set *c) * Bucket priorities/gens: * * For each bucket, we store on disk its - * 8 bit gen - * 16 bit priority + * 8 bit gen + * 16 bit priority * * See alloc.c for an explanation of the gen. The priority is used to implement * lru (and in the future other) cache replacement policies; for most purposes @@ -587,7 +590,7 @@ static void prio_read(struct cache *ca, uint64_t bucket) struct prio_set *p = ca->disk_buckets; struct bucket_disk *d = p->data + prios_per_bucket(ca), *end = d; struct bucket *b; - unsigned bucket_nr = 0; + unsigned int bucket_nr = 0; for (b = ca->buckets; b < ca->buckets + ca->sb.nbuckets; @@ -599,7 +602,8 @@ static void prio_read(struct cache *ca, uint64_t bucket) prio_io(ca, bucket, REQ_OP_READ, 0); - if (p->csum != bch_crc64(&p->magic, bucket_bytes(ca) - 8)) + if (p->csum != + bch_crc64(&p->magic, bucket_bytes(ca) - 8)) pr_warn("bad csum reading priorities"); if (p->magic != pset_magic(&ca->sb)) @@ -619,6 +623,7 @@ static void prio_read(struct cache *ca, uint64_t bucket) static int open_dev(struct block_device *b, fmode_t mode) { struct bcache_device *d = b->bd_disk->private_data; + if (test_bit(BCACHE_DEV_CLOSING, &d->flags)) return -ENXIO; @@ -629,6 +634,7 @@ static int open_dev(struct block_device *b, fmode_t mode) static void release_dev(struct gendisk *b, fmode_t mode) { struct bcache_device *d = b->private_data; + closure_put(&d->cl); } @@ -662,7 +668,7 @@ static void bcache_device_unlink(struct bcache_device *d) lockdep_assert_held(&bch_register_lock); if (d->c && !test_and_set_bit(BCACHE_DEV_UNLINK_DONE, &d->flags)) { - unsigned i; + unsigned int i; struct cache *ca; sysfs_remove_link(&d->c->kobj, d->name); @@ -676,7 +682,7 @@ static void bcache_device_unlink(struct bcache_device *d) static void bcache_device_link(struct bcache_device *d, struct cache_set *c, const char *name) { - unsigned i; + unsigned int i; struct cache *ca; for_each_cache(ca, d->c, i) @@ -715,7 +721,7 @@ static void bcache_device_detach(struct bcache_device *d) } static void bcache_device_attach(struct bcache_device *d, struct cache_set *c, - unsigned id) + unsigned int id) { d->id = id; d->c = c; @@ -762,7 +768,7 @@ static void bcache_device_free(struct bcache_device *d) closure_debug_destroy(&d->cl); } -static int bcache_device_init(struct bcache_device *d, unsigned block_size, +static int bcache_device_init(struct bcache_device *d, unsigned int block_size, sector_t sectors) { struct request_queue *q; @@ -778,7 +784,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size, if (!d->nr_stripes || d->nr_stripes > max_stripes) { pr_err("nr_stripes too large or invalid: %u (start sector beyond end of disk?)", - (unsigned)d->nr_stripes); + (unsigned int)d->nr_stripes); return -ENOMEM; } @@ -919,6 +925,7 @@ void bch_cached_dev_run(struct cached_dev *dc) if (!d->c && BDEV_STATE(&dc->sb) != BDEV_STATE_NONE) { struct closure cl; + closure_init_stack(&cl); SET_BDEV_STATE(&dc->sb, BDEV_STATE_STALE); @@ -928,8 +935,10 @@ void bch_cached_dev_run(struct cached_dev *dc) add_disk(d->disk); bd_link_disk_holder(dc->bdev, dc->disk.disk); - /* won't show up in the uevent file, use udevadm monitor -e instead - * only class / kset properties are persistent */ + /* + * won't show up in the uevent file, use udevadm monitor -e instead + * only class / kset properties are persistent + */ kobject_uevent_env(&disk_to_dev(d->disk)->kobj, KOBJ_CHANGE, env); kfree(env[1]); kfree(env[2]); @@ -976,6 +985,7 @@ static void cached_dev_detach_finish(struct work_struct *w) { struct cached_dev *dc = container_of(w, struct cached_dev, detach); struct closure cl; + closure_init_stack(&cl); BUG_ON(!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)); @@ -1097,12 +1107,14 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, } } - /* Deadlocks since we're called via sysfs... - sysfs_remove_file(&dc->kobj, &sysfs_attach); + /* + * Deadlocks since we're called via sysfs... + * sysfs_remove_file(&dc->kobj, &sysfs_attach); */ if (bch_is_zero(u->uuid, 16)) { struct closure cl; + closure_init_stack(&cl); memcpy(u->uuid, dc->sb.uuid, 16); @@ -1124,11 +1136,11 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, list_move(&dc->list, &c->cached_devs); calc_cached_dev_sectors(c); - smp_wmb(); /* * dc->c must be set before dc->count != 0 - paired with the mb in * cached_dev_get() */ + smp_wmb(); refcount_set(&dc->count, 1); /* Block writeback thread, but spawn it */ @@ -1212,7 +1224,7 @@ static void cached_dev_flush(struct closure *cl) continue_at(cl, cached_dev_free, system_wq); } -static int cached_dev_init(struct cached_dev *dc, unsigned block_size) +static int cached_dev_init(struct cached_dev *dc, unsigned int block_size) { int ret; struct io *io; @@ -1320,6 +1332,7 @@ void bch_flash_dev_release(struct kobject *kobj) static void flash_dev_free(struct closure *cl) { struct bcache_device *d = container_of(cl, struct bcache_device, cl); + mutex_lock(&bch_register_lock); atomic_long_sub(bcache_dev_sectors_dirty(d), &d->c->flash_dev_dirty_sectors); @@ -1459,17 +1472,18 @@ bool bch_cache_set_error(struct cache_set *c, const char *fmt, ...) if (test_and_set_bit(CACHE_SET_IO_DISABLE, &c->flags)) pr_info("CACHE_SET_IO_DISABLE already set"); - /* XXX: we can be called from atomic context - acquire_console_sem(); - */ + /* + * XXX: we can be called from atomic context + * acquire_console_sem(); + */ - printk(KERN_ERR "bcache: error on %pU: ", c->sb.set_uuid); + pr_err("bcache: error on %pU: ", c->sb.set_uuid); va_start(args, fmt); vprintk(fmt, args); va_end(args); - printk(", disabling caching\n"); + pr_err(", disabling caching\n"); if (c->on_error == ON_ERROR_PANIC) panic("panic forced after error\n"); @@ -1481,6 +1495,7 @@ bool bch_cache_set_error(struct cache_set *c, const char *fmt, ...) void bch_cache_set_release(struct kobject *kobj) { struct cache_set *c = container_of(kobj, struct cache_set, kobj); + kfree(c); module_put(THIS_MODULE); } @@ -1489,7 +1504,7 @@ static void cache_set_free(struct closure *cl) { struct cache_set *c = container_of(cl, struct cache_set, cl); struct cache *ca; - unsigned i; + unsigned int i; if (!IS_ERR_OR_NULL(c->debug)) debugfs_remove(c->debug); @@ -1532,7 +1547,7 @@ static void cache_set_flush(struct closure *cl) struct cache_set *c = container_of(cl, struct cache_set, caching); struct cache *ca; struct btree *b; - unsigned i; + unsigned int i; bch_cache_accounting_destroy(&c->accounting); @@ -1671,6 +1686,7 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb) { int iter_size; struct cache_set *c = kzalloc(sizeof(struct cache_set), GFP_KERNEL); + if (!c) return NULL; @@ -1731,8 +1747,8 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb) if (!(c->devices = kcalloc(c->nr_uuids, sizeof(void *), GFP_KERNEL)) || mempool_init_slab_pool(&c->search, 32, bch_search_cache) || mempool_init_kmalloc_pool(&c->bio_meta, 2, - sizeof(struct bbio) + sizeof(struct bio_vec) * - bucket_pages(c)) || + sizeof(struct bbio) + sizeof(struct bio_vec) * + bucket_pages(c)) || mempool_init_kmalloc_pool(&c->fill_iter, 1, iter_size) || bioset_init(&c->bio_split, 4, offsetof(struct bbio, bio), BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER) || @@ -1762,7 +1778,7 @@ static void run_cache_set(struct cache_set *c) struct cached_dev *dc, *t; struct cache *ca; struct closure cl; - unsigned i; + unsigned int i; closure_init_stack(&cl); @@ -1804,7 +1820,9 @@ static void run_cache_set(struct cache_set *c) goto err; err = "error reading btree root"; - c->root = bch_btree_node_get(c, NULL, k, j->btree_level, true, NULL); + c->root = bch_btree_node_get(c, NULL, k, + j->btree_level, + true, NULL); if (IS_ERR_OR_NULL(c->root)) goto err; @@ -1853,7 +1871,7 @@ static void run_cache_set(struct cache_set *c) pr_notice("invalidating existing data"); for_each_cache(ca, c, i) { - unsigned j; + unsigned int j; ca->sb.keys = clamp_t(int, ca->sb.nbuckets >> 7, 2, SB_JOURNAL_BUCKETS); @@ -1998,7 +2016,7 @@ err: void bch_cache_release(struct kobject *kobj) { struct cache *ca = container_of(kobj, struct cache, kobj); - unsigned i; + unsigned int i; if (ca->set) { BUG_ON(ca->set->cache[ca->sb.nr_this_dev] != ca); @@ -2098,7 +2116,9 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, goto err; } - if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache")) { + if (kobject_add(&ca->kobj, + &part_to_dev(bdev->bd_part)->kobj, + "bcache")) { err = "error calling kobject_add"; ret = -ENOMEM; goto out; @@ -2127,13 +2147,14 @@ err: /* Global interfaces/init */ -static ssize_t register_bcache(struct kobject *, struct kobj_attribute *, - const char *, size_t); +static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, + const char *buffer, size_t size); kobj_attribute_write(register, register_bcache); kobj_attribute_write(register_quiet, register_bcache); -static bool bch_is_open_backing(struct block_device *bdev) { +static bool bch_is_open_backing(struct block_device *bdev) +{ struct cache_set *c, *tc; struct cached_dev *dc, *t; @@ -2147,10 +2168,11 @@ static bool bch_is_open_backing(struct block_device *bdev) { return false; } -static bool bch_is_open_cache(struct block_device *bdev) { +static bool bch_is_open_cache(struct block_device *bdev) +{ struct cache_set *c, *tc; struct cache *ca; - unsigned i; + unsigned int i; list_for_each_entry_safe(c, tc, &bch_cache_sets, list) for_each_cache(ca, c, i) @@ -2159,7 +2181,8 @@ static bool bch_is_open_cache(struct block_device *bdev) { return false; } -static bool bch_is_open(struct block_device *bdev) { +static bool bch_is_open(struct block_device *bdev) +{ return bch_is_open_cache(bdev) || bch_is_open_backing(bdev); } @@ -2216,6 +2239,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, err = "failed to register device"; if (SB_IS_BDEV(sb)) { struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL); + if (!dc) goto err_close; @@ -2224,6 +2248,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, mutex_unlock(&bch_register_lock); } else { struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL); + if (!ca) goto err_close; diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index 81d3520b0702..150cf4f4cf74 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -130,8 +130,10 @@ rw_attribute(btree_shrinker_disabled); rw_attribute(copy_gc_enabled); rw_attribute(size); -static ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[], - size_t selected) +static ssize_t bch_snprint_string_list(char *buf, + size_t size, + const char * const list[], + size_t selected) { char *out = buf; size_t i; @@ -148,7 +150,7 @@ SHOW(__bch_cached_dev) { struct cached_dev *dc = container_of(kobj, struct cached_dev, disk.kobj); - const char *states[] = { "no cache", "clean", "dirty", "inconsistent" }; + char const *states[] = { "no cache", "clean", "dirty", "inconsistent" }; int wb = dc->writeback_running; #define var(stat) (dc->stat) @@ -307,7 +309,7 @@ STORE(__cached_dev) if (v < 0) return v; - if ((unsigned) v != BDEV_CACHE_MODE(&dc->sb)) { + if ((unsigned int) v != BDEV_CACHE_MODE(&dc->sb)) { SET_BDEV_CACHE_MODE(&dc->sb, v); bch_write_bdev_super(dc, NULL); } @@ -341,8 +343,9 @@ STORE(__cached_dev) add_uevent_var(env, "DRIVER=bcache"); add_uevent_var(env, "CACHED_UUID=%pU", dc->sb.uuid), add_uevent_var(env, "CACHED_LABEL=%s", buf); - kobject_uevent_env( - &disk_to_dev(dc->disk.disk)->kobj, KOBJ_CHANGE, env->envp); + kobject_uevent_env(&disk_to_dev(dc->disk.disk)->kobj, + KOBJ_CHANGE, + env->envp); kfree(env); } @@ -459,6 +462,7 @@ STORE(__bch_flash_dev) if (attr == &sysfs_size) { uint64_t v; + strtoi_h_or_return(buf, v); u->sectors = v >> 9; @@ -533,9 +537,9 @@ static int bch_bset_print_stats(struct cache_set *c, char *buf) op.stats.floats, op.stats.failed); } -static unsigned bch_root_usage(struct cache_set *c) +static unsigned int bch_root_usage(struct cache_set *c) { - unsigned bytes = 0; + unsigned int bytes = 0; struct bkey *k; struct btree *b; struct btree_iter iter; @@ -570,9 +574,9 @@ static size_t bch_cache_size(struct cache_set *c) return ret; } -static unsigned bch_cache_max_chain(struct cache_set *c) +static unsigned int bch_cache_max_chain(struct cache_set *c) { - unsigned ret = 0; + unsigned int ret = 0; struct hlist_head *h; mutex_lock(&c->bucket_lock); @@ -580,7 +584,7 @@ static unsigned bch_cache_max_chain(struct cache_set *c) for (h = c->bucket_hash; h < c->bucket_hash + (1 << BUCKET_HASH_BITS); h++) { - unsigned i = 0; + unsigned int i = 0; struct hlist_node *p; hlist_for_each(p, h) @@ -593,13 +597,13 @@ static unsigned bch_cache_max_chain(struct cache_set *c) return ret; } -static unsigned bch_btree_used(struct cache_set *c) +static unsigned int bch_btree_used(struct cache_set *c) { return div64_u64(c->gc_stats.key_bytes * 100, (c->gc_stats.nodes ?: 1) * btree_bytes(c)); } -static unsigned bch_average_key_size(struct cache_set *c) +static unsigned int bch_average_key_size(struct cache_set *c) { return c->gc_stats.nkeys ? div64_u64(c->gc_stats.data, c->gc_stats.nkeys) @@ -703,6 +707,7 @@ STORE(__bch_cache_set) if (attr == &sysfs_flash_vol_create) { int r; uint64_t v; + strtoi_h_or_return(buf, v); r = bch_flash_dev_create(c, v); @@ -736,6 +741,7 @@ STORE(__bch_cache_set) if (attr == &sysfs_prune_cache) { struct shrink_control sc; + sc.gfp_mask = GFP_KERNEL; sc.nr_to_scan = strtoul_or_return(buf); c->shrink.scan_objects(&c->shrink, &sc); @@ -789,12 +795,14 @@ STORE_LOCKED(bch_cache_set) SHOW(bch_cache_set_internal) { struct cache_set *c = container_of(kobj, struct cache_set, internal); + return bch_cache_set_show(&c->kobj, attr, buf); } STORE(bch_cache_set_internal) { struct cache_set *c = container_of(kobj, struct cache_set, internal); + return bch_cache_set_store(&c->kobj, attr, buf, size); } @@ -996,7 +1004,7 @@ STORE(__bch_cache) if (v < 0) return v; - if ((unsigned) v != CACHE_REPLACEMENT(&ca->sb)) { + if ((unsigned int) v != CACHE_REPLACEMENT(&ca->sb)) { mutex_lock(&ca->set->bucket_lock); SET_CACHE_REPLACEMENT(&ca->sb, v); mutex_unlock(&ca->set->bucket_lock); diff --git a/drivers/md/bcache/sysfs.h b/drivers/md/bcache/sysfs.h index b54fe9602529..3fe82425859c 100644 --- a/drivers/md/bcache/sysfs.h +++ b/drivers/md/bcache/sysfs.h @@ -44,9 +44,9 @@ STORE(fn) \ static struct attribute sysfs_##_name = \ { .name = #_name, .mode = _mode } -#define write_attribute(n) __sysfs_attribute(n, S_IWUSR) -#define read_attribute(n) __sysfs_attribute(n, S_IRUGO) -#define rw_attribute(n) __sysfs_attribute(n, S_IRUGO|S_IWUSR) +#define write_attribute(n) __sysfs_attribute(n, 0200) +#define read_attribute(n) __sysfs_attribute(n, 0444) +#define rw_attribute(n) __sysfs_attribute(n, 0644) #define sysfs_printf(file, fmt, ...) \ do { \ diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c index b15256bcf0e7..20eddeac1531 100644 --- a/drivers/md/bcache/util.c +++ b/drivers/md/bcache/util.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * random utiility code, for bcache but in theory not specific to bcache * @@ -133,6 +134,7 @@ bool bch_is_zero(const char *p, size_t n) int bch_parse_uuid(const char *s, char *uuid) { size_t i, j, x; + memset(uuid, 0, 16); for (i = 0, j = 0; @@ -279,134 +281,3 @@ int bch_bio_alloc_pages(struct bio *bio, gfp_t gfp_mask) return 0; } - -/* - * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group (Any - * use permitted, subject to terms of PostgreSQL license; see.) - - * If we have a 64-bit integer type, then a 64-bit CRC looks just like the - * usual sort of implementation. (See Ross Williams' excellent introduction - * A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS, available from - * ftp://ftp.rocksoft.com/papers/crc_v3.txt or several other net sites.) - * If we have no working 64-bit type, then fake it with two 32-bit registers. - * - * The present implementation is a normal (not "reflected", in Williams' - * terms) 64-bit CRC, using initial all-ones register contents and a final - * bit inversion. The chosen polynomial is borrowed from the DLT1 spec - * (ECMA-182, available from http://www.ecma.ch/ecma1/STAND/ECMA-182.HTM): - * - * x^64 + x^62 + x^57 + x^55 + x^54 + x^53 + x^52 + x^47 + x^46 + x^45 + - * x^40 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 + - * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 + - * x^7 + x^4 + x + 1 -*/ - -static const uint64_t crc_table[256] = { - 0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL, - 0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL, - 0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL, - 0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL, - 0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL, - 0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL, - 0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL, - 0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL, - 0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL, - 0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL, - 0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL, - 0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL, - 0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL, - 0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL, - 0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL, - 0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL, - 0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL, - 0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL, - 0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL, - 0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL, - 0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL, - 0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL, - 0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL, - 0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL, - 0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL, - 0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL, - 0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL, - 0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL, - 0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL, - 0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL, - 0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL, - 0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL, - 0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL, - 0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL, - 0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL, - 0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL, - 0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL, - 0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL, - 0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL, - 0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL, - 0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL, - 0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL, - 0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL, - 0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL, - 0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL, - 0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL, - 0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL, - 0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL, - 0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL, - 0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL, - 0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL, - 0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL, - 0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL, - 0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL, - 0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL, - 0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL, - 0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL, - 0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL, - 0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL, - 0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL, - 0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL, - 0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL, - 0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL, - 0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL, - 0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL, - 0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL, - 0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL, - 0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL, - 0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL, - 0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL, - 0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL, - 0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL, - 0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL, - 0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL, - 0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL, - 0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL, - 0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL, - 0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL, - 0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL, - 0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL, - 0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL, - 0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL, - 0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL, - 0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL, - 0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL, - 0x9AFCE626CE85B507ULL, -}; - -uint64_t bch_crc64_update(uint64_t crc, const void *_data, size_t len) -{ - const unsigned char *data = _data; - - while (len--) { - int i = ((int) (crc >> 56) ^ *data++) & 0xFF; - crc = crc_table[i] ^ (crc << 8); - } - - return crc; -} - -uint64_t bch_crc64(const void *data, size_t len) -{ - uint64_t crc = 0xffffffffffffffffULL; - - crc = bch_crc64_update(crc, data, len); - - return crc ^ 0xffffffffffffffffULL; -} diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h index f7b0133c9d2f..00aab6abcfe4 100644 --- a/drivers/md/bcache/util.h +++ b/drivers/md/bcache/util.h @@ -11,6 +11,7 @@ #include <linux/ratelimit.h> #include <linux/vmalloc.h> #include <linux/workqueue.h> +#include <linux/crc64.h> #include "closure.h" @@ -288,10 +289,10 @@ do { \ #define ANYSINT_MAX(t) \ ((((t) 1 << (sizeof(t) * 8 - 2)) - (t) 1) * (t) 2 + (t) 1) -int bch_strtoint_h(const char *, int *); -int bch_strtouint_h(const char *, unsigned int *); -int bch_strtoll_h(const char *, long long *); -int bch_strtoull_h(const char *, unsigned long long *); +int bch_strtoint_h(const char *cp, int *res); +int bch_strtouint_h(const char *cp, unsigned int *res); +int bch_strtoll_h(const char *cp, long long *res); +int bch_strtoull_h(const char *cp, unsigned long long *res); static inline int bch_strtol_h(const char *cp, long *res) { @@ -347,7 +348,7 @@ static inline int bch_strtoul_h(const char *cp, long *res) snprintf(buf, size, \ __builtin_types_compatible_p(typeof(var), int) \ ? "%i\n" : \ - __builtin_types_compatible_p(typeof(var), unsigned) \ + __builtin_types_compatible_p(typeof(var), unsigned int) \ ? "%u\n" : \ __builtin_types_compatible_p(typeof(var), long) \ ? "%li\n" : \ @@ -379,7 +380,7 @@ struct time_stats { void bch_time_stats_update(struct time_stats *stats, uint64_t time); -static inline unsigned local_clock_us(void) +static inline unsigned int local_clock_us(void) { return local_clock() >> 10; } @@ -402,7 +403,8 @@ do { \ __print_time_stat(stats, name, \ average_duration, duration_units); \ sysfs_print(name ## _ ##max_duration ## _ ## duration_units, \ - div_u64((stats)->max_duration, NSEC_PER_ ## duration_units));\ + div_u64((stats)->max_duration, \ + NSEC_PER_ ## duration_units)); \ \ sysfs_print(name ## _last_ ## frequency_units, (stats)->last \ ? div_s64(local_clock() - (stats)->last, \ @@ -542,10 +544,27 @@ dup: \ #define RB_PREV(ptr, member) \ container_of_or_null(rb_prev(&(ptr)->member), typeof(*ptr), member) +static inline uint64_t bch_crc64(const void *p, size_t len) +{ + uint64_t crc = 0xffffffffffffffffULL; + + crc = crc64_be(crc, p, len); + return crc ^ 0xffffffffffffffffULL; +} + +static inline uint64_t bch_crc64_update(uint64_t crc, + const void *p, + size_t len) +{ + crc = crc64_be(crc, p, len); + return crc; +} + /* Does linear interpolation between powers of two */ -static inline unsigned fract_exp_two(unsigned x, unsigned fract_bits) +static inline unsigned int fract_exp_two(unsigned int x, + unsigned int fract_bits) { - unsigned fract = x & ~(~0 << fract_bits); + unsigned int fract = x & ~(~0 << fract_bits); x >>= fract_bits; x = 1 << x; @@ -561,8 +580,4 @@ static inline sector_t bdev_sectors(struct block_device *bdev) { return bdev->bd_inode->i_size >> 9; } - -uint64_t bch_crc64_update(uint64_t, const void *, size_t); -uint64_t bch_crc64(const void *, size_t); - #endif /* _BCACHE_UTIL_H */ diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 481d4cf38ac0..08c3a9f9676c 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -215,7 +215,8 @@ static void update_writeback_rate(struct work_struct *work) smp_mb(); } -static unsigned writeback_delay(struct cached_dev *dc, unsigned sectors) +static unsigned int writeback_delay(struct cached_dev *dc, + unsigned int sectors) { if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) || !dc->writeback_percent) @@ -249,6 +250,7 @@ static void dirty_init(struct keybuf_key *w) static void dirty_io_destructor(struct closure *cl) { struct dirty_io *io = container_of(cl, struct dirty_io, cl); + kfree(io); } @@ -263,7 +265,7 @@ static void write_dirty_finish(struct closure *cl) /* This is kind of a dumb way of signalling errors. */ if (KEY_DIRTY(&w->key)) { int ret; - unsigned i; + unsigned int i; struct keylist keys; bch_keylist_init(&keys); @@ -377,7 +379,7 @@ static void read_dirty_submit(struct closure *cl) static void read_dirty(struct cached_dev *dc) { - unsigned delay = 0; + unsigned int delay = 0; struct keybuf_key *next, *keys[MAX_WRITEBACKS_IN_PASS], *w; size_t size; int nk, i; @@ -442,7 +444,8 @@ static void read_dirty(struct cached_dev *dc) io = kzalloc(sizeof(struct dirty_io) + sizeof(struct bio_vec) * - DIV_ROUND_UP(KEY_SIZE(&w->key), PAGE_SECTORS), + DIV_ROUND_UP(KEY_SIZE(&w->key), + PAGE_SECTORS), GFP_KERNEL); if (!io) goto err; @@ -465,7 +468,8 @@ static void read_dirty(struct cached_dev *dc) down(&dc->in_flight); - /* We've acquired a semaphore for the maximum + /* + * We've acquired a semaphore for the maximum * simultaneous number of writebacks; from here * everything happens asynchronously. */ @@ -498,11 +502,11 @@ err: /* Scan for dirty data */ -void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode, +void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned int inode, uint64_t offset, int nr_sectors) { struct bcache_device *d = c->devices[inode]; - unsigned stripe_offset, stripe, sectors_dirty; + unsigned int stripe_offset, stripe, sectors_dirty; if (!d) return; @@ -514,7 +518,7 @@ void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode, stripe_offset = offset & (d->stripe_size - 1); while (nr_sectors) { - int s = min_t(unsigned, abs(nr_sectors), + int s = min_t(unsigned int, abs(nr_sectors), d->stripe_size - stripe_offset); if (nr_sectors < 0) @@ -538,7 +542,9 @@ void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode, static bool dirty_pred(struct keybuf *buf, struct bkey *k) { - struct cached_dev *dc = container_of(buf, struct cached_dev, writeback_keys); + struct cached_dev *dc = container_of(buf, + struct cached_dev, + writeback_keys); BUG_ON(KEY_INODE(k) != dc->disk.id); @@ -548,7 +554,7 @@ static bool dirty_pred(struct keybuf *buf, struct bkey *k) static void refill_full_stripes(struct cached_dev *dc) { struct keybuf *buf = &dc->writeback_keys; - unsigned start_stripe, stripe, next_stripe; + unsigned int start_stripe, stripe, next_stripe; bool wrapped = false; stripe = offset_to_stripe(&dc->disk, KEY_OFFSET(&buf->last_scanned)); @@ -679,8 +685,10 @@ static int bch_writeback_thread(void *arg) * data on cache. BCACHE_DEV_DETACHING flag is set in * bch_cached_dev_detach(). */ - if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) + if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) { + up_write(&dc->writeback_lock); break; + } } up_write(&dc->writeback_lock); @@ -688,7 +696,7 @@ static int bch_writeback_thread(void *arg) read_dirty(dc); if (searched_full_index) { - unsigned delay = dc->writeback_delay * HZ; + unsigned int delay = dc->writeback_delay * HZ; while (delay && !kthread_should_stop() && @@ -712,7 +720,7 @@ static int bch_writeback_thread(void *arg) struct sectors_dirty_init { struct btree_op op; - unsigned inode; + unsigned int inode; size_t count; struct bkey start; }; diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h index 3745d7004c47..d2b9fdbc8994 100644 --- a/drivers/md/bcache/writeback.h +++ b/drivers/md/bcache/writeback.h @@ -28,7 +28,7 @@ static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d) return ret; } -static inline unsigned offset_to_stripe(struct bcache_device *d, +static inline unsigned int offset_to_stripe(struct bcache_device *d, uint64_t offset) { do_div(offset, d->stripe_size); @@ -37,9 +37,9 @@ static inline unsigned offset_to_stripe(struct bcache_device *d, static inline bool bcache_dev_stripe_dirty(struct cached_dev *dc, uint64_t offset, - unsigned nr_sectors) + unsigned int nr_sectors) { - unsigned stripe = offset_to_stripe(&dc->disk, offset); + unsigned int stripe = offset_to_stripe(&dc->disk, offset); while (1) { if (atomic_read(dc->disk.stripe_sectors_dirty + stripe)) @@ -54,9 +54,9 @@ static inline bool bcache_dev_stripe_dirty(struct cached_dev *dc, } static inline bool should_writeback(struct cached_dev *dc, struct bio *bio, - unsigned cache_mode, bool would_skip) + unsigned int cache_mode, bool would_skip) { - unsigned in_use = dc->disk.c->gc_stats.in_use; + unsigned int in_use = dc->disk.c->gc_stats.in_use; if (cache_mode != CACHE_MODE_WRITEBACK || test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) || @@ -96,10 +96,11 @@ static inline void bch_writeback_add(struct cached_dev *dc) } } -void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int); +void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned int inode, + uint64_t offset, int nr_sectors); -void bch_sectors_dirty_init(struct bcache_device *); -void bch_cached_dev_writeback_init(struct cached_dev *); -int bch_cached_dev_writeback_start(struct cached_dev *); +void bch_sectors_dirty_init(struct bcache_device *d); +void bch_cached_dev_writeback_init(struct cached_dev *dc); +int bch_cached_dev_writeback_start(struct cached_dev *dc); #endif diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c index 3a28a68f184c..5f1f80d424dd 100644 --- a/drivers/md/dm-writecache.c +++ b/drivers/md/dm-writecache.c @@ -268,9 +268,8 @@ static int persistent_memory_claim(struct dm_writecache *wc) i = 0; do { long daa; - void *dummy_addr; daa = dax_direct_access(wc->ssd_dev->dax_dev, i, p - i, - &dummy_addr, &pfn); + NULL, &pfn); if (daa <= 0) { r = daa ? daa : -EINVAL; goto err3; diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 16dffa06c913..dd2078b27a41 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -21,6 +21,7 @@ struct cec_notifier { struct list_head head; struct kref kref; struct device *dev; + const char *conn; struct cec_adapter *cec_adap; void (*callback)(struct cec_adapter *adap, u16 pa); @@ -30,13 +31,14 @@ struct cec_notifier { static LIST_HEAD(cec_notifiers); static DEFINE_MUTEX(cec_notifiers_lock); -struct cec_notifier *cec_notifier_get(struct device *dev) +struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) { struct cec_notifier *n; mutex_lock(&cec_notifiers_lock); list_for_each_entry(n, &cec_notifiers, head) { - if (n->dev == dev) { + if (n->dev == dev && + (!conn || !strcmp(n->conn, conn))) { kref_get(&n->kref); mutex_unlock(&cec_notifiers_lock); return n; @@ -46,6 +48,8 @@ struct cec_notifier *cec_notifier_get(struct device *dev) if (!n) goto unlock; n->dev = dev; + if (conn) + n->conn = kstrdup(conn, GFP_KERNEL); n->phys_addr = CEC_PHYS_ADDR_INVALID; mutex_init(&n->lock); kref_init(&n->kref); @@ -54,7 +58,7 @@ unlock: mutex_unlock(&cec_notifiers_lock); return n; } -EXPORT_SYMBOL_GPL(cec_notifier_get); +EXPORT_SYMBOL_GPL(cec_notifier_get_conn); static void cec_notifier_release(struct kref *kref) { @@ -62,6 +66,7 @@ static void cec_notifier_release(struct kref *kref) container_of(kref, struct cec_notifier, kref); list_del(&n->head); + kfree(n->conn); kfree(n); } diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index f3acbb57d48c..35a93b251aab 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -1311,10 +1311,10 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, memcpy(&buf[3], val, len); if (lock) - i2c_lock_adapter(client->adapter); + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); ret = __i2c_transfer(client->adapter, msg, 1); if (lock) - i2c_unlock_adapter(client->adapter); + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); if (ret < 0) { goto err; } else if (ret != 1) { @@ -1352,10 +1352,10 @@ static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, buf[2] = cmd; if (lock) - i2c_lock_adapter(client->adapter); + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); ret = __i2c_transfer(client->adapter, msg, 2); if (lock) - i2c_unlock_adapter(client->adapter); + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); if (ret < 0) { goto err; } else if (ret != 2) { diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index f1886945a7bc..84ac3f73f8fe 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -213,7 +213,7 @@ static inline u32 log10times100(u32 value) static int drxk_i2c_lock(struct drxk_state *state) { - i2c_lock_adapter(state->i2c); + i2c_lock_bus(state->i2c, I2C_LOCK_SEGMENT); state->drxk_i2c_exclusive_lock = true; return 0; @@ -224,7 +224,7 @@ static void drxk_i2c_unlock(struct drxk_state *state) if (!state->drxk_i2c_exclusive_lock) return; - i2c_unlock_adapter(state->i2c); + i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT); state->drxk_i2c_exclusive_lock = false; } diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index adc9046d5a90..c0659568471b 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c @@ -24,9 +24,9 @@ static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg, struct rtl2830_dev *dev = i2c_get_clientdata(client); int ret; - i2c_lock_adapter(client->adapter); + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); ret = regmap_bulk_write(dev->regmap, reg, val, val_count); - i2c_unlock_adapter(client->adapter); + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); return ret; } @@ -36,9 +36,9 @@ static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg, struct rtl2830_dev *dev = i2c_get_clientdata(client); int ret; - i2c_lock_adapter(client->adapter); + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); ret = regmap_update_bits(dev->regmap, reg, mask, val); - i2c_unlock_adapter(client->adapter); + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); return ret; } @@ -48,9 +48,9 @@ static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg, struct rtl2830_dev *dev = i2c_get_clientdata(client); int ret; - i2c_lock_adapter(client->adapter); + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); ret = regmap_bulk_read(dev->regmap, reg, val, val_count); - i2c_unlock_adapter(client->adapter); + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); return ret; } diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c index d402e4b722ca..e506f66657bb 100644 --- a/drivers/media/dvb-frontends/tda1004x.c +++ b/drivers/media/dvb-frontends/tda1004x.c @@ -329,7 +329,7 @@ static int tda1004x_do_upload(struct tda1004x_state *state, tda1004x_write_byteI(state, dspCodeCounterReg, 0); fw_msg.addr = state->config->demod_address; - i2c_lock_adapter(state->i2c); + i2c_lock_bus(state->i2c, I2C_LOCK_SEGMENT); buf[0] = dspCodeInReg; while (pos != len) { // work out how much to send this time @@ -342,14 +342,14 @@ static int tda1004x_do_upload(struct tda1004x_state *state, fw_msg.len = tx_size + 1; if (__i2c_transfer(state->i2c, &fw_msg, 1) != 1) { printk(KERN_ERR "tda1004x: Error during firmware upload\n"); - i2c_unlock_adapter(state->i2c); + i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT); return -EIO; } pos += tx_size; dprintk("%s: fw_pos=0x%x\n", __func__, pos); } - i2c_unlock_adapter(state->i2c); + i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT); /* give the DSP a chance to settle 03/10/05 Hac */ msleep(100); diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index fcdf3d5dc4b6..3bae24b15eaa 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -585,18 +585,12 @@ int __must_check media_device_register_entity(struct media_device *mdev, entity->num_links = 0; entity->num_backlinks = 0; - if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL)) - return -ENOMEM; - - mutex_lock(&mdev->graph_mutex); - - ret = ida_get_new_above(&mdev->entity_internal_idx, 1, - &entity->internal_idx); - if (ret < 0) { - mutex_unlock(&mdev->graph_mutex); + ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL); + if (ret < 0) return ret; - } + entity->internal_idx = ret; + mutex_lock(&mdev->graph_mutex); mdev->entity_internal_idx_max = max(mdev->entity_internal_idx_max, entity->internal_idx); @@ -642,7 +636,7 @@ static void __media_device_unregister_entity(struct media_entity *entity) struct media_interface *intf; unsigned int i; - ida_simple_remove(&mdev->entity_internal_idx, entity->internal_idx); + ida_free(&mdev->entity_internal_idx, entity->internal_idx); /* Remove all interface links pointing to this entity */ list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) { diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index b25c8d3c1c31..94c1fe0e9787 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -536,6 +536,17 @@ menuconfig CEC_PLATFORM_DRIVERS if CEC_PLATFORM_DRIVERS +config VIDEO_CROS_EC_CEC + tristate "ChromeOS EC CEC driver" + depends on MFD_CROS_EC + select CEC_CORE + select CEC_NOTIFIER + ---help--- + If you say yes here you will get support for the + ChromeOS Embedded Controller's CEC. + The CEC bus is present in the HDMI connector and enables communication + between compatible devices. + config VIDEO_MESON_AO_CEC tristate "Amlogic Meson AO CEC driver" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 08640ba87fc2..41322ab65802 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -94,3 +94,5 @@ obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom/camss/ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ obj-y += meson/ + +obj-y += cros-ec-cec/ diff --git a/drivers/media/platform/cros-ec-cec/Makefile b/drivers/media/platform/cros-ec-cec/Makefile new file mode 100644 index 000000000000..9ce97f93febe --- /dev/null +++ b/drivers/media/platform/cros-ec-cec/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_CROS_EC_CEC) += cros-ec-cec.o diff --git a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c new file mode 100644 index 000000000000..7bc4d8a9af28 --- /dev/null +++ b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * CEC driver for ChromeOS Embedded Controller + * + * Copyright (c) 2018 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/dmi.h> +#include <linux/pci.h> +#include <linux/cec.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <media/cec.h> +#include <media/cec-notifier.h> +#include <linux/mfd/cros_ec.h> +#include <linux/mfd/cros_ec_commands.h> + +#define DRV_NAME "cros-ec-cec" + +/** + * struct cros_ec_cec - Driver data for EC CEC + * + * @cros_ec: Pointer to EC device + * @notifier: Notifier info for responding to EC events + * @adap: CEC adapter + * @notify: CEC notifier pointer + * @rx_msg: storage for a received message + */ +struct cros_ec_cec { + struct cros_ec_device *cros_ec; + struct notifier_block notifier; + struct cec_adapter *adap; + struct cec_notifier *notify; + struct cec_msg rx_msg; +}; + +static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) +{ + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + uint8_t *cec_message = cros_ec->event_data.data.cec_message; + unsigned int len = cros_ec->event_size; + + cros_ec_cec->rx_msg.len = len; + memcpy(cros_ec_cec->rx_msg.msg, cec_message, len); + + cec_received_msg(cros_ec_cec->adap, &cros_ec_cec->rx_msg); +} + +static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) +{ + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + uint32_t events = cros_ec->event_data.data.cec_events; + + if (events & EC_MKBP_CEC_SEND_OK) + cec_transmit_attempt_done(cros_ec_cec->adap, + CEC_TX_STATUS_OK); + + /* FW takes care of all retries, tell core to avoid more retries */ + if (events & EC_MKBP_CEC_SEND_FAILED) + cec_transmit_attempt_done(cros_ec_cec->adap, + CEC_TX_STATUS_MAX_RETRIES | + CEC_TX_STATUS_NACK); +} + +static int cros_ec_cec_event(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *_notify) +{ + struct cros_ec_cec *cros_ec_cec; + struct cros_ec_device *cros_ec; + + cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier); + cros_ec = cros_ec_cec->cros_ec; + + if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) { + handle_cec_event(cros_ec_cec); + return NOTIFY_OK; + } + + if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) { + handle_cec_message(cros_ec_cec); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct { + struct cros_ec_command msg; + struct ec_params_cec_set data; + } __packed msg = {}; + int ret; + + msg.msg.command = EC_CMD_CEC_SET; + msg.msg.outsize = sizeof(msg.data); + msg.data.cmd = CEC_CMD_LOGICAL_ADDRESS; + msg.data.val = logical_addr; + + ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + if (ret < 0) { + dev_err(cros_ec->dev, + "error setting CEC logical address on EC: %d\n", ret); + return ret; + } + + return 0; +} + +static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *cec_msg) +{ + struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct { + struct cros_ec_command msg; + struct ec_params_cec_write data; + } __packed msg = {}; + int ret; + + msg.msg.command = EC_CMD_CEC_WRITE_MSG; + msg.msg.outsize = cec_msg->len; + memcpy(msg.data.msg, cec_msg->msg, cec_msg->len); + + ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + if (ret < 0) { + dev_err(cros_ec->dev, + "error writing CEC msg on EC: %d\n", ret); + return ret; + } + + return 0; +} + +static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct { + struct cros_ec_command msg; + struct ec_params_cec_set data; + } __packed msg = {}; + int ret; + + msg.msg.command = EC_CMD_CEC_SET; + msg.msg.outsize = sizeof(msg.data); + msg.data.cmd = CEC_CMD_ENABLE; + msg.data.val = enable; + + ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + if (ret < 0) { + dev_err(cros_ec->dev, + "error %sabling CEC on EC: %d\n", + (enable ? "en" : "dis"), ret); + return ret; + } + + return 0; +} + +static const struct cec_adap_ops cros_ec_cec_ops = { + .adap_enable = cros_ec_cec_adap_enable, + .adap_log_addr = cros_ec_cec_set_log_addr, + .adap_transmit = cros_ec_cec_transmit, +}; + +#ifdef CONFIG_PM_SLEEP +static int cros_ec_cec_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(cros_ec_cec->cros_ec->irq); + + return 0; +} + +static int cros_ec_cec_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(cros_ec_cec->cros_ec->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, + cros_ec_cec_suspend, cros_ec_cec_resume); + +#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) + +/* + * The Firmware only handles a single CEC interface tied to a single HDMI + * connector we specify along with the DRM device name handling the HDMI output + */ + +struct cec_dmi_match { + char *sys_vendor; + char *product_name; + char *devname; + char *conn; +}; + +static const struct cec_dmi_match cec_dmi_match_table[] = { + /* Google Fizz */ + { "Google", "Fizz", "0000:00:02.0", "Port B" }, +}; + +static int cros_ec_cec_get_notifier(struct device *dev, + struct cec_notifier **notify) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) { + const struct cec_dmi_match *m = &cec_dmi_match_table[i]; + + if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) && + dmi_match(DMI_PRODUCT_NAME, m->product_name)) { + struct device *d; + + /* Find the device, bail out if not yet registered */ + d = bus_find_device_by_name(&pci_bus_type, NULL, + m->devname); + if (!d) + return -EPROBE_DEFER; + + *notify = cec_notifier_get_conn(d, m->conn); + return 0; + } + } + + /* Hardware support must be added in the cec_dmi_match_table */ + dev_warn(dev, "CEC notifier not configured for this hardware\n"); + + return -ENODEV; +} + +#else + +static int cros_ec_cec_get_notifier(struct device *dev, + struct cec_notifier **notify) +{ + return -ENODEV; +} + +#endif + +static int cros_ec_cec_probe(struct platform_device *pdev) +{ + struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); + struct cros_ec_device *cros_ec = ec_dev->ec_dev; + struct cros_ec_cec *cros_ec_cec; + int ret; + + cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), + GFP_KERNEL); + if (!cros_ec_cec) + return -ENOMEM; + + platform_set_drvdata(pdev, cros_ec_cec); + cros_ec_cec->cros_ec = cros_ec; + + ret = cros_ec_cec_get_notifier(&pdev->dev, &cros_ec_cec->notify); + if (ret) + return ret; + + ret = device_init_wakeup(&pdev->dev, 1); + if (ret) { + dev_err(&pdev->dev, "failed to initialize wakeup\n"); + return ret; + } + + cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, + DRV_NAME, CEC_CAP_DEFAULTS, 1); + if (IS_ERR(cros_ec_cec->adap)) + return PTR_ERR(cros_ec_cec->adap); + + /* Get CEC events from the EC. */ + cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; + ret = blocking_notifier_chain_register(&cros_ec->event_notifier, + &cros_ec_cec->notifier); + if (ret) { + dev_err(&pdev->dev, "failed to register notifier\n"); + cec_delete_adapter(cros_ec_cec->adap); + return ret; + } + + ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); + if (ret < 0) { + cec_delete_adapter(cros_ec_cec->adap); + return ret; + } + + cec_register_cec_notifier(cros_ec_cec->adap, cros_ec_cec->notify); + + return 0; +} + +static int cros_ec_cec_remove(struct platform_device *pdev) +{ + struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int ret; + + ret = blocking_notifier_chain_unregister( + &cros_ec_cec->cros_ec->event_notifier, + &cros_ec_cec->notifier); + + if (ret) { + dev_err(dev, "failed to unregister notifier\n"); + return ret; + } + + cec_unregister_adapter(cros_ec_cec->adap); + + if (cros_ec_cec->notify) + cec_notifier_put(cros_ec_cec->notify); + + return 0; +} + +static struct platform_driver cros_ec_cec_driver = { + .probe = cros_ec_cec_probe, + .remove = cros_ec_cec_remove, + .driver = { + .name = DRV_NAME, + .pm = &cros_ec_cec_pm_ops, + }, +}; + +module_platform_driver(cros_ec_cec_driver); + +MODULE_DESCRIPTION("CEC driver for ChromeOS ECs"); +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 7e81cd887c13..054b3b747dae 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -225,7 +225,7 @@ static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, */ if (lock_i2c) { tda18271_i2c_gate_ctrl(fe, 1); - i2c_lock_adapter(priv->i2c_props.adap); + i2c_lock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT); } while (len) { if (max > len) @@ -246,7 +246,7 @@ static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, len -= max; } if (lock_i2c) { - i2c_unlock_adapter(priv->i2c_props.adap); + i2c_unlock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT); tda18271_i2c_gate_ctrl(fe, 0); } @@ -300,7 +300,7 @@ int tda18271_init_regs(struct dvb_frontend *fe) * as those could cause bad things */ tda18271_i2c_gate_ctrl(fe, 1); - i2c_lock_adapter(priv->i2c_props.adap); + i2c_lock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT); /* initialize registers */ switch (priv->id) { @@ -516,7 +516,7 @@ int tda18271_init_regs(struct dvb_frontend *fe) /* synchronize */ __tda18271_write_regs(fe, R_EP1, 1, false); - i2c_unlock_adapter(priv->i2c_props.adap); + i2c_unlock_bus(priv->i2c_props.adap, I2C_LOCK_SEGMENT); tda18271_i2c_gate_ctrl(fe, 0); return 0; diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index bb93cc53554e..bd25faf6d13d 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -672,13 +672,6 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } - err = tegra_mc_reset_setup(mc); - if (err < 0) { - dev_err(&pdev->dev, "failed to register reset controller: %d\n", - err); - return err; - } - mc->irq = platform_get_irq(pdev, 0); if (mc->irq < 0) { dev_err(&pdev->dev, "interrupt not specified\n"); @@ -697,13 +690,16 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } + err = tegra_mc_reset_setup(mc); + if (err < 0) + dev_err(&pdev->dev, "failed to register reset controller: %d\n", + err); + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); - if (IS_ERR(mc->smmu)) { + if (IS_ERR(mc->smmu)) dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", PTR_ERR(mc->smmu)); - return PTR_ERR(mc->smmu); - } } return 0; diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c index 632651f4b6e8..2250d03ea17f 100644 --- a/drivers/memory/ti-emif-pm.c +++ b/drivers/memory/ti-emif-pm.c @@ -249,6 +249,34 @@ static const struct of_device_id ti_emif_of_match[] = { }; MODULE_DEVICE_TABLE(of, ti_emif_of_match); +#ifdef CONFIG_PM_SLEEP +static int ti_emif_resume(struct device *dev) +{ + unsigned long tmp = + __raw_readl((void *)emif_instance->ti_emif_sram_virt); + + /* + * Check to see if what we are copying is already present in the + * first byte at the destination, only copy if it is not which + * indicates we have lost context and sram no longer contains + * the PM code + */ + if (tmp != ti_emif_sram) + ti_emif_push_sram(dev, emif_instance); + + return 0; +} + +static int ti_emif_suspend(struct device *dev) +{ + /* + * The contents will be present in DDR hence no need to + * explicitly save + */ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + static int ti_emif_probe(struct platform_device *pdev) { int ret; @@ -308,12 +336,17 @@ static int ti_emif_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops ti_emif_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ti_emif_suspend, ti_emif_resume) +}; + static struct platform_driver ti_emif_driver = { .probe = ti_emif_probe, .remove = ti_emif_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(ti_emif_of_match), + .pm = &ti_emif_pm_ops, }, }; module_platform_driver(ti_emif_driver); diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index 84e313107233..7b9052ea7413 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -146,14 +146,14 @@ int pm860x_page_reg_write(struct i2c_client *i2c, int reg, unsigned char zero; int ret; - i2c_lock_adapter(i2c->adapter); + i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT); read_device(i2c, 0xFA, 0, &zero); read_device(i2c, 0xFB, 0, &zero); read_device(i2c, 0xFF, 0, &zero); ret = write_device(i2c, reg, 1, &data); read_device(i2c, 0xFE, 0, &zero); read_device(i2c, 0xFC, 0, &zero); - i2c_unlock_adapter(i2c->adapter); + i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT); return ret; } EXPORT_SYMBOL(pm860x_page_reg_write); @@ -164,14 +164,14 @@ int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, unsigned char zero = 0; int ret; - i2c_lock_adapter(i2c->adapter); + i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT); read_device(i2c, 0xfa, 0, &zero); read_device(i2c, 0xfb, 0, &zero); read_device(i2c, 0xff, 0, &zero); ret = read_device(i2c, reg, count, buf); read_device(i2c, 0xFE, 0, &zero); read_device(i2c, 0xFC, 0, &zero); - i2c_unlock_adapter(i2c->adapter); + i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT); return ret; } EXPORT_SYMBOL(pm860x_page_bulk_read); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b860eb5aa194..11841f4b7b2b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -202,26 +202,6 @@ config MFD_CROS_EC You also need to enable the driver for the bus you are using. The protocol for talking to the EC is defined by the bus driver. -config MFD_CROS_EC_I2C - tristate "ChromeOS Embedded Controller (I2C)" - depends on MFD_CROS_EC && I2C - - help - If you say Y here, you get support for talking to the ChromeOS - EC through an I2C bus. This uses a simple byte-level protocol with - a checksum. Failing accesses will be retried three times to - improve reliability. - -config MFD_CROS_EC_SPI - tristate "ChromeOS Embedded Controller (SPI)" - depends on MFD_CROS_EC && SPI - - ---help--- - If you say Y here, you get support for talking to the ChromeOS EC - through a SPI bus, using a byte-level protocol. Since the EC's - response time cannot be guaranteed, we support ignoring - 'pre-amble' bytes before the response actually starts. - config MFD_CROS_EC_CHARDEV tristate "Chrome OS Embedded Controller userspace device interface" depends on MFD_CROS_EC @@ -232,6 +212,56 @@ config MFD_CROS_EC_CHARDEV If you have a supported Chromebook, choose Y or M here. The module will be called cros_ec_dev. +config MFD_MADERA + tristate "Cirrus Logic Madera codecs" + select MFD_CORE + select REGMAP + select REGMAP_IRQ + select MADERA_IRQ + select PINCTRL + select PINCTRL_MADERA + help + Support for the Cirrus Logic Madera platform audio codecs + +config MFD_MADERA_I2C + tristate "Cirrus Logic Madera codecs with I2C" + depends on MFD_MADERA + depends on I2C + select REGMAP_I2C + help + Support for the Cirrus Logic Madera platform audio SoC + core functionality controlled via I2C. + +config MFD_MADERA_SPI + tristate "Cirrus Logic Madera codecs with SPI" + depends on MFD_MADERA + depends on SPI_MASTER + select REGMAP_SPI + help + Support for the Cirrus Logic Madera platform audio SoC + core functionality controlled via SPI. + +config MFD_CS47L35 + bool "Cirrus Logic CS47L35" + select PINCTRL_CS47L35 + depends on MFD_MADERA + help + Support for Cirrus Logic CS47L35 Smart Codec + +config MFD_CS47L85 + bool "Cirrus Logic CS47L85" + select PINCTRL_CS47L85 + depends on MFD_MADERA + help + Support for Cirrus Logic CS47L85 Smart Codec + +config MFD_CS47L90 + bool "Cirrus Logic CS47L90/91" + select PINCTRL_CS47L90 + depends on MFD_MADERA + help + Support for Cirrus Logic CS47L90 and CS47L91 Smart Codecs + config MFD_ASIC3 bool "Compaq ASIC3" depends on GPIOLIB && ARM @@ -1787,6 +1817,19 @@ config MFD_STW481X in various ST Microelectronics and ST-Ericsson embedded Nomadik series. +config MFD_ROHM_BD718XX + tristate "ROHM BD71837 Power Management IC" + depends on I2C=y + depends on OF + select REGMAP_I2C + select REGMAP_IRQ + select MFD_CORE + help + Select this option to get support for the ROHM BD71837 + Power Management ICs. BD71837 is designed to power processors like + NXP i.MX8. It contains 8 BUCK outputs and 7 LDOs, voltage monitoring + and emergency shut down as well as 32,768KHz clock output. + config MFD_STM32_LPTIMER tristate "Support for STM32 Low-Power Timer" depends on (ARCH_STM32 && OF) || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index e9fd20dba18d..5856a9489cbd 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -14,8 +14,6 @@ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o cros_ec_core-objs := cros_ec.o obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o -obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o -obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o @@ -72,6 +70,20 @@ wm8994-objs := wm8994-core.o wm8994-irq.o wm8994-regmap.o obj-$(CONFIG_MFD_WM8994) += wm8994.o obj-$(CONFIG_MFD_WM97xx) += wm97xx-core.o +madera-objs := madera-core.o +ifeq ($(CONFIG_MFD_CS47L35),y) +madera-objs += cs47l35-tables.o +endif +ifeq ($(CONFIG_MFD_CS47L85),y) +madera-objs += cs47l85-tables.o +endif +ifeq ($(CONFIG_MFD_CS47L90),y) +madera-objs += cs47l90-tables.o +endif +obj-$(CONFIG_MFD_MADERA) += madera.o +obj-$(CONFIG_MFD_MADERA_I2C) += madera-i2c.o +obj-$(CONFIG_MFD_MADERA_SPI) += madera-spi.o + obj-$(CONFIG_TPS6105X) += tps6105x.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS6507X) += tps6507x.o @@ -227,4 +239,5 @@ obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o +obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 83f1c5a516d9..5f1e37d23943 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -24,6 +24,7 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/machine.h> #include <linux/slab.h> +#include <linux/ktime.h> #include <linux/platform_device.h> #include <linux/mfd/arizona/core.h> @@ -236,22 +237,39 @@ static irqreturn_t arizona_overclocked(int irq, void *data) #define ARIZONA_REG_POLL_DELAY_US 7500 +static inline bool arizona_poll_reg_delay(ktime_t timeout) +{ + if (ktime_compare(ktime_get(), timeout) > 0) + return false; + + usleep_range(ARIZONA_REG_POLL_DELAY_US / 2, ARIZONA_REG_POLL_DELAY_US); + + return true; +} + static int arizona_poll_reg(struct arizona *arizona, int timeout_ms, unsigned int reg, unsigned int mask, unsigned int target) { + ktime_t timeout = ktime_add_us(ktime_get(), timeout_ms * USEC_PER_MSEC); unsigned int val = 0; int ret; - ret = regmap_read_poll_timeout(arizona->regmap, - reg, val, ((val & mask) == target), - ARIZONA_REG_POLL_DELAY_US, - timeout_ms * 1000); - if (ret) - dev_err(arizona->dev, "Polling reg 0x%x timed out: %x\n", - reg, val); + do { + ret = regmap_read(arizona->regmap, reg, &val); - return ret; + if ((val & mask) == target) + return 0; + } while (arizona_poll_reg_delay(timeout)); + + if (ret) { + dev_err(arizona->dev, "Failed polling reg 0x%x: %d\n", + reg, ret); + return ret; + } + + dev_err(arizona->dev, "Polling reg 0x%x timed out: %x\n", reg, val); + return -ETIMEDOUT; } static int arizona_wait_for_boot(struct arizona *arizona) diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c index f87342c211bc..4d069ed21ff6 100644 --- a/drivers/mfd/as3722.c +++ b/drivers/mfd/as3722.c @@ -349,6 +349,8 @@ static int as3722_i2c_of_probe(struct i2c_client *i2c, "ams,enable-internal-int-pullup"); as3722->en_intern_i2c_pullup = of_property_read_bool(np, "ams,enable-internal-i2c-pullup"); + as3722->en_ac_ok_pwr_on = of_property_read_bool(np, + "ams,enable-ac-ok-power-on"); as3722->irq_flags = irqd_get_trigger_type(irq_data); dev_dbg(&i2c->dev, "IRQ flags are 0x%08lx\n", as3722->irq_flags); return 0; @@ -360,6 +362,7 @@ static int as3722_i2c_probe(struct i2c_client *i2c, struct as3722 *as3722; unsigned long irq_flags; int ret; + u8 val = 0; as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL); if (!as3722) @@ -398,6 +401,15 @@ static int as3722_i2c_probe(struct i2c_client *i2c, if (ret < 0) return ret; + if (as3722->en_ac_ok_pwr_on) + val = AS3722_CTRL_SEQU1_AC_OK_PWR_ON; + ret = as3722_update_bits(as3722, AS3722_CTRL_SEQU1_REG, + AS3722_CTRL_SEQU1_AC_OK_PWR_ON, val); + if (ret < 0) { + dev_err(as3722->dev, "CTRLsequ1 update failed: %d\n", ret); + return ret; + } + ret = devm_mfd_add_devices(&i2c->dev, -1, as3722_devs, ARRAY_SIZE(as3722_devs), NULL, 0, regmap_irq_get_domain(as3722->irq_data)); diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index d35a5fe6c950..a7b7c5423ea5 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = { { .compatible = "x-powers,axp202", .data = (void *)AXP202_ID }, { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID }, { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID }, + { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, { }, }; MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match); @@ -74,6 +75,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = { { "axp202", 0 }, { "axp209", 0 }, { "axp221", 0 }, + { "axp806", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 9a2ef3d9b8f8..0be511dd93d0 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -221,6 +221,11 @@ static const struct resource axp803_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; +static const struct resource axp806_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP806_IRQ_POK_RISE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP806_IRQ_POK_FALL, "PEK_DBF"), +}; + static const struct resource axp809_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_RIS_EDGE, "PEK_DBR"), DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_FAL_EDGE, "PEK_DBF"), @@ -730,6 +735,15 @@ static const struct mfd_cell axp803_cells[] = { { .name = "axp20x-regulator" }, }; +static const struct mfd_cell axp806_self_working_cells[] = { + { + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp806_pek_resources), + .resources = axp806_pek_resources, + }, + { .name = "axp20x-regulator" }, +}; + static const struct mfd_cell axp806_cells[] = { { .id = 2, @@ -842,8 +856,14 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_irq_chip = &axp803_regmap_irq_chip; break; case AXP806_ID: - axp20x->nr_cells = ARRAY_SIZE(axp806_cells); - axp20x->cells = axp806_cells; + if (of_property_read_bool(axp20x->dev->of_node, + "x-powers,self-working-mode")) { + axp20x->nr_cells = ARRAY_SIZE(axp806_self_working_cells); + axp20x->cells = axp806_self_working_cells; + } else { + axp20x->nr_cells = ARRAY_SIZE(axp806_cells); + axp20x->cells = axp806_cells; + } axp20x->regmap_cfg = &axp806_regmap_config; axp20x->regmap_irq_chip = &axp806_regmap_irq_chip; break; @@ -901,7 +921,9 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) */ if (axp20x->variant == AXP806_ID) { if (of_property_read_bool(axp20x->dev->of_node, - "x-powers,master-mode")) + "x-powers,master-mode") || + of_property_read_bool(axp20x->dev->of_node, + "x-powers,self-working-mode")) regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT, AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE); else diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 27af62ed480a..999dac752bcc 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -378,10 +378,18 @@ error: kfree(msg); } +static const struct mfd_cell cros_ec_cec_cells[] = { + { .name = "cros-ec-cec" } +}; + static const struct mfd_cell cros_ec_rtc_cells[] = { { .name = "cros-ec-rtc" } }; +static const struct mfd_cell cros_usbpd_charger_cells[] = { + { .name = "cros-usbpd-charger" } +}; + static int ec_device_probe(struct platform_device *pdev) { int retval = -ENOMEM; @@ -420,6 +428,18 @@ static int ec_device_probe(struct platform_device *pdev) if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) cros_ec_sensors_register(ec); + /* Check whether this EC instance has CEC host command support */ + if (cros_ec_check_features(ec, EC_FEATURE_CEC)) { + retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, + cros_ec_cec_cells, + ARRAY_SIZE(cros_ec_cec_cells), + NULL, 0, NULL); + if (retval) + dev_err(ec->dev, + "failed to add cros-ec-cec device: %d\n", + retval); + } + /* Check whether this EC instance has RTC host command support */ if (cros_ec_check_features(ec, EC_FEATURE_RTC)) { retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, @@ -432,6 +452,18 @@ static int ec_device_probe(struct platform_device *pdev) retval); } + /* Check whether this EC instance has the PD charge manager */ + if (cros_ec_check_features(ec, EC_FEATURE_USB_PD)) { + retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, + cros_usbpd_charger_cells, + ARRAY_SIZE(cros_usbpd_charger_cells), + NULL, 0, NULL); + if (retval) + dev_err(ec->dev, + "failed to add cros-usbpd-charger device: %d\n", + retval); + } + /* Take control of the lightbar from the EC. */ lb_manual_suspend_ctrl(ec, 1); diff --git a/drivers/mfd/cs47l35-tables.c b/drivers/mfd/cs47l35-tables.c new file mode 100644 index 000000000000..604c9dd14df5 --- /dev/null +++ b/drivers/mfd/cs47l35-tables.c @@ -0,0 +1,1609 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Regmap tables for CS47L35 codec + * + * Copyright (C) 2015-2017 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/registers.h> + +#include "madera.h" + +static const struct reg_sequence cs47l35_reva_16_patch[] = { + { 0x460, 0x0c40 }, + { 0x461, 0xcd1a }, + { 0x462, 0x0c40 }, + { 0x463, 0xb53b }, + { 0x464, 0x0c40 }, + { 0x465, 0x7503 }, + { 0x466, 0x0c40 }, + { 0x467, 0x4a41 }, + { 0x468, 0x0041 }, + { 0x469, 0x3491 }, + { 0x46a, 0x0841 }, + { 0x46b, 0x1f50 }, + { 0x46c, 0x0446 }, + { 0x46d, 0x14ed }, + { 0x46e, 0x0446 }, + { 0x46f, 0x1455 }, + { 0x470, 0x04c6 }, + { 0x471, 0x1220 }, + { 0x472, 0x04c6 }, + { 0x473, 0x040f }, + { 0x474, 0x04ce }, + { 0x475, 0x0339 }, + { 0x476, 0x05df }, + { 0x477, 0x028f }, + { 0x478, 0x05df }, + { 0x479, 0x0209 }, + { 0x47a, 0x05df }, + { 0x47b, 0x00cf }, + { 0x47c, 0x05df }, + { 0x47d, 0x0001 }, + { 0x47e, 0x07ff }, +}; + +int cs47l35_patch(struct madera *madera) +{ + int ret; + + ret = regmap_register_patch(madera->regmap, cs47l35_reva_16_patch, + ARRAY_SIZE(cs47l35_reva_16_patch)); + if (ret < 0) + dev_err(madera->dev, "Error applying patch: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs47l35_patch); + +static const struct reg_default cs47l35_reg_default[] = { + { 0x00000020, 0x0000 }, /* R32 (0x20) - Tone Generator 1 */ + { 0x00000021, 0x1000 }, /* R33 (0x21) - Tone Generator 2 */ + { 0x00000022, 0x0000 }, /* R34 (0x22) - Tone Generator 3 */ + { 0x00000023, 0x1000 }, /* R35 (0x23) - Tone Generator 4 */ + { 0x00000024, 0x0000 }, /* R36 (0x24) - Tone Generator 5 */ + { 0x00000030, 0x0000 }, /* R48 (0x30) - PWM Drive 1 */ + { 0x00000031, 0x0100 }, /* R49 (0x31) - PWM Drive 2 */ + { 0x00000032, 0x0100 }, /* R50 (0x32) - PWM Drive 3 */ + { 0x00000061, 0x01ff }, /* R97 (0x61) - Sample Rate Sequence Select 1 */ + { 0x00000062, 0x01ff }, /* R98 (0x62) - Sample Rate Sequence Select 2 */ + { 0x00000063, 0x01ff }, /* R99 (0x63) - Sample Rate Sequence Select 3 */ + { 0x00000064, 0x01ff }, /* R100 (0x64) - Sample Rate Sequence Select 4*/ + { 0x00000066, 0x01ff }, /* R102 (0x66) - Always On Triggers Sequence Select 1*/ + { 0x00000067, 0x01ff }, /* R103 (0x67) - Always On Triggers Sequence Select 2*/ + { 0x00000090, 0x0000 }, /* R144 (0x90) - Haptics Control 1 */ + { 0x00000091, 0x7fff }, /* R145 (0x91) - Haptics Control 2 */ + { 0x00000092, 0x0000 }, /* R146 (0x92) - Haptics phase 1 intensity */ + { 0x00000093, 0x0000 }, /* R147 (0x93) - Haptics phase 1 duration */ + { 0x00000094, 0x0000 }, /* R148 (0x94) - Haptics phase 2 intensity */ + { 0x00000095, 0x0000 }, /* R149 (0x95) - Haptics phase 2 duration */ + { 0x00000096, 0x0000 }, /* R150 (0x96) - Haptics phase 3 intensity */ + { 0x00000097, 0x0000 }, /* R151 (0x97) - Haptics phase 3 duration */ + { 0x000000A0, 0x0000 }, /* R160 (0xa0) - Comfort Noise Generator */ + { 0x00000100, 0x0002 }, /* R256 (0x100) - Clock 32k 1 */ + { 0x00000101, 0x0404 }, /* R257 (0x101) - System Clock 1 */ + { 0x00000102, 0x0011 }, /* R258 (0x102) - Sample rate 1 */ + { 0x00000103, 0x0011 }, /* R259 (0x103) - Sample rate 2 */ + { 0x00000104, 0x0011 }, /* R260 (0x104) - Sample rate 3 */ + { 0x00000120, 0x0305 }, /* R288 (0x120) - DSP Clock 1 */ + { 0x00000122, 0x0000 }, /* R290 (0x122) - DSP Clock 2 */ + { 0x00000149, 0x0000 }, /* R329 (0x149) - Output system clock */ + { 0x0000014a, 0x0000 }, /* R330 (0x14a) - Output async clock */ + { 0x00000152, 0x0000 }, /* R338 (0x152) - Rate Estimator 1 */ + { 0x00000153, 0x0000 }, /* R339 (0x153) - Rate Estimator 2 */ + { 0x00000154, 0x0000 }, /* R340 (0x154) - Rate Estimator 3 */ + { 0x00000155, 0x0000 }, /* R341 (0x155) - Rate Estimator 4 */ + { 0x00000156, 0x0000 }, /* R342 (0x156) - Rate Estimator 5 */ + { 0x00000171, 0x0002 }, /* R369 (0x171) - FLL1 Control 1 */ + { 0x00000172, 0x0008 }, /* R370 (0x172) - FLL1 Control 2 */ + { 0x00000173, 0x0018 }, /* R371 (0x173) - FLL1 Control 3 */ + { 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */ + { 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */ + { 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */ + { 0x00000177, 0x0281 }, /* R375 (0x177) - FLL1 Loop Filter Test 1 */ + { 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */ + { 0x0000017a, 0x0b06 }, /* R378 (0x17a) - FLL1 EFS2 */ + { 0x0000017f, 0x0000 }, /* R383 (0x17f) - FLL1 Synchroniser 1 */ + { 0x00000180, 0x0000 }, /* R384 (0x180) - FLL1 Synchroniser 2 */ + { 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 3 */ + { 0x00000182, 0x0000 }, /* R386 (0x182) - FLL1 Synchroniser 4 */ + { 0x00000183, 0x0000 }, /* R387 (0x183) - FLL1 Synchroniser 5 */ + { 0x00000184, 0x0000 }, /* R388 (0x184) - FLL1 Synchroniser 6 */ + { 0x00000185, 0x0001 }, /* R389 (0x185) - FLL1 Synchroniser 7 */ + { 0x00000187, 0x0000 }, /* R391 (0x187) - FLL1 Spread Spectrum */ + { 0x00000188, 0x000c }, /* R392 (0x188) - FLL1 GPIO Clock */ + { 0x00000200, 0x0006 }, /* R512 (0x200) - Mic Charge Pump 1 */ + { 0x0000020b, 0x0400 }, /* R523 (0x20b) - HP Charge Pump 8 */ + { 0x00000213, 0x03e4 }, /* R531 (0x213) - LDO2 Control 1 */ + { 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */ + { 0x00000219, 0x00e6 }, /* R537 (0x219) - Mic Bias Ctrl 2 */ + { 0x0000021c, 0x0022 }, /* R540 (0x21c) - Mic Bias Ctrl 5 */ + { 0x0000021e, 0x0022 }, /* R542 (0x21e) - Mic Bias Ctrl 6 */ + { 0x0000027e, 0x0000 }, /* R638 (0x27e) - EDRE HP stereo control */ + { 0x00000293, 0x0080 }, /* R659 (0x293) - Accessory Detect Mode 1 */ + { 0x0000029b, 0x0000 }, /* R667 (0x29b) - Headphone Detect 1 */ + { 0x000002a3, 0x1102 }, /* R675 (0x2a3) - Mic Detect Control 1 */ + { 0x000002a4, 0x009f }, /* R676 (0x2a4) - Mic Detect Control 2 */ + { 0x000002a6, 0x3d3d }, /* R678 (0x2a6) - Mic Detect Level 1 */ + { 0x000002a7, 0x3d3d }, /* R679 (0x2a7) - Mic Detect Level 2 */ + { 0x000002a8, 0x333d }, /* R680 (0x2a8) - Mic Detect Level 3 */ + { 0x000002a9, 0x202d }, /* R681 (0x2a9) - Mic Detect Level 4 */ + { 0x000002c6, 0x0010 }, /* R710 (0x2c5) - Mic Clamp control */ + { 0x000002c8, 0x0000 }, /* R712 (0x2c8) - GP switch 1 */ + { 0x000002d3, 0x0000 }, /* R723 (0x2d3) - Jack detect analogue */ + { 0x00000300, 0x0000 }, /* R768 (0x300) - Input Enables */ + { 0x00000308, 0x0000 }, /* R776 (0x308) - Input Rate */ + { 0x00000309, 0x0022 }, /* R777 (0x309) - Input Volume Ramp */ + { 0x0000030c, 0x0002 }, /* R780 (0x30c) - HPF Control */ + { 0x00000310, 0x0080 }, /* R784 (0x310) - IN1L Control */ + { 0x00000311, 0x0180 }, /* R785 (0x311) - ADC Digital Volume 1L */ + { 0x00000312, 0x0500 }, /* R786 (0x312) - DMIC1L Control */ + { 0x00000314, 0x0080 }, /* R788 (0x314) - IN1R Control */ + { 0x00000315, 0x0180 }, /* R789 (0x315) - ADC Digital Volume 1R */ + { 0x00000316, 0x0000 }, /* R790 (0x316) - DMIC1R Control */ + { 0x00000318, 0x0080 }, /* R792 (0x318) - IN2L Control */ + { 0x00000319, 0x0180 }, /* R793 (0x319) - ADC Digital Volume 2L */ + { 0x0000031a, 0x0500 }, /* R794 (0x31a) - DMIC2L Control */ + { 0x0000031c, 0x0080 }, /* R796 (0x31c) - IN2R Control */ + { 0x0000031d, 0x0180 }, /* R797 (0x31d) - ADC Digital Volume 2R */ + { 0x0000031e, 0x0000 }, /* R798 (0x31e) - DMIC2R Control */ + { 0x00000400, 0x0000 }, /* R1024 (0x400) - Output Enables 1 */ + { 0x00000408, 0x0000 }, /* R1032 (0x408) - Output Rate 1 */ + { 0x00000409, 0x0022 }, /* R1033 (0x409) - Output Volume Ramp */ + { 0x00000410, 0x0080 }, /* R1040 (0x410) - Output Path Config 1L */ + { 0x00000411, 0x0180 }, /* R1041 (0x411) - DAC Digital Volume 1L */ + { 0x00000413, 0x0001 }, /* R1043 (0x413) - Noise Gate Select 1L */ + { 0x00000414, 0x0080 }, /* R1044 (0x414) - Output Path Config 1R */ + { 0x00000415, 0x0180 }, /* R1045 (0x415) - DAC Digital Volume 1R */ + { 0x00000417, 0x0002 }, /* R1047 (0x417) - Noise Gate Select 1R */ + { 0x00000428, 0x0000 }, /* R1064 (0x428) - Output Path Config 4L */ + { 0x00000429, 0x0180 }, /* R1065 (0x429) - DAC Digital Volume 4L */ + { 0x0000042b, 0x0040 }, /* R1067 (0x42b) - Noise Gate Select 4L */ + { 0x00000430, 0x0000 }, /* R1072 (0x430) - Output Path Config 5L */ + { 0x00000431, 0x0180 }, /* R1073 (0x431) - DAC Digital Volume 5L */ + { 0x00000433, 0x0100 }, /* R1075 (0x433) - Noise Gate Select 5L */ + { 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */ + { 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */ + { 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */ + { 0x00000440, 0x0003 }, /* R1088 (0x440) - DRE Enable */ + { 0x00000448, 0x0a83 }, /* R1096 (0x448) - eDRE Enable */ + { 0x0000044a, 0x0000 }, /* R1098 (0x44a) - eDRE Manual */ + { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ + { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ + { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ + { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ + { 0x000004a0, 0x3080 }, /* R1184 (0x4a0) - HP1 Short Circuit Ctrl */ + { 0x000004a8, 0x7120 }, /* R1192 (0x4a8) - HP Test Ctrl 5 */ + { 0x000004a9, 0x7120 }, /* R1193 (0x4a9) - HP Test Ctrl 6 */ + { 0x00000500, 0x000c }, /* R1280 (0x500) - AIF1 BCLK Ctrl */ + { 0x00000501, 0x0000 }, /* R1281 (0x501) - AIF1 Tx Pin Ctrl */ + { 0x00000502, 0x0000 }, /* R1282 (0x502) - AIF1 Rx Pin Ctrl */ + { 0x00000503, 0x0000 }, /* R1283 (0x503) - AIF1 Rate Ctrl */ + { 0x00000504, 0x0000 }, /* R1284 (0x504) - AIF1 Format */ + { 0x00000506, 0x0040 }, /* R1286 (0x506) - AIF1 Rx BCLK Rate */ + { 0x00000507, 0x1818 }, /* R1287 (0x507) - AIF1 Frame Ctrl 1 */ + { 0x00000508, 0x1818 }, /* R1288 (0x508) - AIF1 Frame Ctrl 2 */ + { 0x00000509, 0x0000 }, /* R1289 (0x509) - AIF1 Frame Ctrl 3 */ + { 0x0000050a, 0x0001 }, /* R1290 (0x50a) - AIF1 Frame Ctrl 4 */ + { 0x0000050b, 0x0002 }, /* R1291 (0x50b) - AIF1 Frame Ctrl 5 */ + { 0x0000050c, 0x0003 }, /* R1292 (0x50c) - AIF1 Frame Ctrl 6 */ + { 0x0000050d, 0x0004 }, /* R1293 (0x50d) - AIF1 Frame Ctrl 7 */ + { 0x0000050e, 0x0005 }, /* R1294 (0x50e) - AIF1 Frame Ctrl 8 */ + { 0x00000511, 0x0000 }, /* R1297 (0x511) - AIF1 Frame Ctrl 11 */ + { 0x00000512, 0x0001 }, /* R1298 (0x512) - AIF1 Frame Ctrl 12 */ + { 0x00000513, 0x0002 }, /* R1299 (0x513) - AIF1 Frame Ctrl 13 */ + { 0x00000514, 0x0003 }, /* R1300 (0x514) - AIF1 Frame Ctrl 14 */ + { 0x00000515, 0x0004 }, /* R1301 (0x515) - AIF1 Frame Ctrl 15 */ + { 0x00000516, 0x0005 }, /* R1302 (0x516) - AIF1 Frame Ctrl 16 */ + { 0x00000519, 0x0000 }, /* R1305 (0x519) - AIF1 Tx Enables */ + { 0x0000051a, 0x0000 }, /* R1306 (0x51a) - AIF1 Rx Enables */ + { 0x00000540, 0x000c }, /* R1344 (0x540) - AIF2 BCLK Ctrl */ + { 0x00000541, 0x0000 }, /* R1345 (0x541) - AIF2 Tx Pin Ctrl */ + { 0x00000542, 0x0000 }, /* R1346 (0x542) - AIF2 Rx Pin Ctrl */ + { 0x00000543, 0x0000 }, /* R1347 (0x543) - AIF2 Rate Ctrl */ + { 0x00000544, 0x0000 }, /* R1348 (0x544) - AIF2 Format */ + { 0x00000546, 0x0040 }, /* R1350 (0x546) - AIF2 Rx BCLK Rate */ + { 0x00000547, 0x1818 }, /* R1351 (0x547) - AIF2 Frame Ctrl 1 */ + { 0x00000548, 0x1818 }, /* R1352 (0x548) - AIF2 Frame Ctrl 2 */ + { 0x00000549, 0x0000 }, /* R1353 (0x549) - AIF2 Frame Ctrl 3 */ + { 0x0000054a, 0x0001 }, /* R1354 (0x54a) - AIF2 Frame Ctrl 4 */ + { 0x00000551, 0x0000 }, /* R1361 (0x551) - AIF2 Frame Ctrl 11 */ + { 0x00000552, 0x0001 }, /* R1362 (0x552) - AIF2 Frame Ctrl 12 */ + { 0x00000559, 0x0000 }, /* R1369 (0x559) - AIF2 Tx Enables */ + { 0x0000055a, 0x0000 }, /* R1370 (0x55a) - AIF2 Rx Enables */ + { 0x00000580, 0x000c }, /* R1408 (0x580) - AIF3 BCLK Ctrl */ + { 0x00000581, 0x0000 }, /* R1409 (0x581) - AIF3 Tx Pin Ctrl */ + { 0x00000582, 0x0000 }, /* R1410 (0x582) - AIF3 Rx Pin Ctrl */ + { 0x00000583, 0x0000 }, /* R1411 (0x583) - AIF3 Rate Ctrl */ + { 0x00000584, 0x0000 }, /* R1412 (0x584) - AIF3 Format */ + { 0x00000586, 0x0040 }, /* R1414 (0x586) - AIF3 Rx BCLK Rate */ + { 0x00000587, 0x1818 }, /* R1415 (0x587) - AIF3 Frame Ctrl 1 */ + { 0x00000588, 0x1818 }, /* R1416 (0x588) - AIF3 Frame Ctrl 2 */ + { 0x00000589, 0x0000 }, /* R1417 (0x589) - AIF3 Frame Ctrl 3 */ + { 0x0000058a, 0x0001 }, /* R1418 (0x58a) - AIF3 Frame Ctrl 4 */ + { 0x00000591, 0x0000 }, /* R1425 (0x591) - AIF3 Frame Ctrl 11 */ + { 0x00000592, 0x0001 }, /* R1426 (0x592) - AIF3 Frame Ctrl 12 */ + { 0x00000599, 0x0000 }, /* R1433 (0x599) - AIF3 Tx Enables */ + { 0x0000059a, 0x0000 }, /* R1434 (0x59a) - AIF3 Rx Enables */ + { 0x000005c2, 0x0000 }, /* R1474 (0x5c2) - SPD1 TX Control */ + { 0x000005e3, 0x0000 }, /* R1507 (0x5e3) - SLIMbus Framer Ref Gear */ + { 0x000005e5, 0x0000 }, /* R1509 (0x5e5) - SLIMbus Rates 1 */ + { 0x000005e6, 0x0000 }, /* R1510 (0x5e6) - SLIMbus Rates 2 */ + { 0x000005e7, 0x0000 }, /* R1511 (0x5e7) - SLIMbus Rates 3 */ + { 0x000005e9, 0x0000 }, /* R1513 (0x5e9) - SLIMbus Rates 5 */ + { 0x000005ea, 0x0000 }, /* R1514 (0x5ea) - SLIMbus Rates 6 */ + { 0x000005eb, 0x0000 }, /* R1515 (0x5eb) - SLIMbus Rates 7 */ + { 0x000005f5, 0x0000 }, /* R1525 (0x5f5) - SLIMbus RX Channel Enable */ + { 0x000005f6, 0x0000 }, /* R1526 (0x5f6) - SLIMbus TX Channel Enable */ + { 0x00000640, 0x0000 }, /* R1600 (0x640) - PWM1MIX Input 1 Source */ + { 0x00000641, 0x0080 }, /* R1601 (0x641) - PWM1MIX Input 1 Volume */ + { 0x00000642, 0x0000 }, /* R1602 (0x642) - PWM1MIX Input 2 Source */ + { 0x00000643, 0x0080 }, /* R1603 (0x643) - PWM1MIX Input 2 Volume */ + { 0x00000644, 0x0000 }, /* R1604 (0x644) - PWM1MIX Input 3 Source */ + { 0x00000645, 0x0080 }, /* R1605 (0x645) - PWM1MIX Input 3 Volume */ + { 0x00000646, 0x0000 }, /* R1606 (0x646) - PWM1MIX Input 4 Source */ + { 0x00000647, 0x0080 }, /* R1607 (0x647) - PWM1MIX Input 4 Volume */ + { 0x00000648, 0x0000 }, /* R1608 (0x648) - PWM2MIX Input 1 Source */ + { 0x00000649, 0x0080 }, /* R1609 (0x649) - PWM2MIX Input 1 Volume */ + { 0x0000064a, 0x0000 }, /* R1610 (0x64a) - PWM2MIX Input 2 Source */ + { 0x0000064b, 0x0080 }, /* R1611 (0x64b) - PWM2MIX Input 2 Volume */ + { 0x0000064c, 0x0000 }, /* R1612 (0x64c) - PWM2MIX Input 3 Source */ + { 0x0000064d, 0x0080 }, /* R1613 (0x64d) - PWM2MIX Input 3 Volume */ + { 0x0000064e, 0x0000 }, /* R1614 (0x64e) - PWM2MIX Input 4 Source */ + { 0x0000064f, 0x0080 }, /* R1615 (0x64f) - PWM2MIX Input 4 Volume */ + { 0x00000680, 0x0000 }, /* R1664 (0x680) - OUT1LMIX Input 1 Source */ + { 0x00000681, 0x0080 }, /* R1665 (0x681) - OUT1LMIX Input 1 Volume */ + { 0x00000682, 0x0000 }, /* R1666 (0x682) - OUT1LMIX Input 2 Source */ + { 0x00000683, 0x0080 }, /* R1667 (0x683) - OUT1LMIX Input 2 Volume */ + { 0x00000684, 0x0000 }, /* R1668 (0x684) - OUT1LMIX Input 3 Source */ + { 0x00000685, 0x0080 }, /* R1669 (0x685) - OUT1LMIX Input 3 Volume */ + { 0x00000686, 0x0000 }, /* R1670 (0x686) - OUT1LMIX Input 4 Source */ + { 0x00000687, 0x0080 }, /* R1671 (0x687) - OUT1LMIX Input 4 Volume */ + { 0x00000688, 0x0000 }, /* R1672 (0x688) - OUT1RMIX Input 1 Source */ + { 0x00000689, 0x0080 }, /* R1673 (0x689) - OUT1RMIX Input 1 Volume */ + { 0x0000068a, 0x0000 }, /* R1674 (0x68a) - OUT1RMIX Input 2 Source */ + { 0x0000068b, 0x0080 }, /* R1675 (0x68b) - OUT1RMIX Input 2 Volume */ + { 0x0000068c, 0x0000 }, /* R1672 (0x68c) - OUT1RMIX Input 3 Source */ + { 0x0000068d, 0x0080 }, /* R1673 (0x68d) - OUT1RMIX Input 3 Volume */ + { 0x0000068e, 0x0000 }, /* R1674 (0x68e) - OUT1RMIX Input 4 Source */ + { 0x0000068f, 0x0080 }, /* R1675 (0x68f) - OUT1RMIX Input 4 Volume */ + { 0x000006b0, 0x0000 }, /* R1712 (0x6b0) - OUT4LMIX Input 1 Source */ + { 0x000006b1, 0x0080 }, /* R1713 (0x6b1) - OUT4LMIX Input 1 Volume */ + { 0x000006b2, 0x0000 }, /* R1714 (0x6b2) - OUT4LMIX Input 2 Source */ + { 0x000006b3, 0x0080 }, /* R1715 (0x6b3) - OUT4LMIX Input 2 Volume */ + { 0x000006b4, 0x0000 }, /* R1716 (0x6b4) - OUT4LMIX Input 3 Source */ + { 0x000006b5, 0x0080 }, /* R1717 (0x6b5) - OUT4LMIX Input 3 Volume */ + { 0x000006b6, 0x0000 }, /* R1718 (0x6b6) - OUT4LMIX Input 4 Source */ + { 0x000006b7, 0x0080 }, /* R1719 (0x6b7) - OUT4LMIX Input 4 Volume */ + { 0x000006c0, 0x0000 }, /* R1728 (0x6c0) - OUT5LMIX Input 1 Source */ + { 0x000006c1, 0x0080 }, /* R1729 (0x6c1) - OUT5LMIX Input 1 Volume */ + { 0x000006c2, 0x0000 }, /* R1730 (0x6c2) - OUT5LMIX Input 2 Source */ + { 0x000006c3, 0x0080 }, /* R1731 (0x6c3) - OUT5LMIX Input 2 Volume */ + { 0x000006c4, 0x0000 }, /* R1732 (0x6c4) - OUT5LMIX Input 3 Source */ + { 0x000006c5, 0x0080 }, /* R1733 (0x6c5) - OUT5LMIX Input 3 Volume */ + { 0x000006c6, 0x0000 }, /* R1734 (0x6c6) - OUT5LMIX Input 4 Source */ + { 0x000006c7, 0x0080 }, /* R1735 (0x6c7) - OUT5LMIX Input 4 Volume */ + { 0x000006c8, 0x0000 }, /* R1736 (0x6c8) - OUT5RMIX Input 1 Source */ + { 0x000006c9, 0x0080 }, /* R1737 (0x6c9) - OUT5RMIX Input 1 Volume */ + { 0x000006ca, 0x0000 }, /* R1738 (0x6ca) - OUT5RMIX Input 2 Source */ + { 0x000006cb, 0x0080 }, /* R1739 (0x6cb) - OUT5RMIX Input 2 Volume */ + { 0x000006cc, 0x0000 }, /* R1740 (0x6cc) - OUT5RMIX Input 3 Source */ + { 0x000006cd, 0x0080 }, /* R1741 (0x6cd) - OUT5RMIX Input 3 Volume */ + { 0x000006ce, 0x0000 }, /* R1742 (0x6ce) - OUT5RMIX Input 4 Source */ + { 0x000006cf, 0x0080 }, /* R1743 (0x6cf) - OUT5RMIX Input 4 Volume */ + { 0x00000700, 0x0000 }, /* R1792 (0x700) - AIF1TX1MIX Input 1 Source */ + { 0x00000701, 0x0080 }, /* R1793 (0x701) - AIF1TX1MIX Input 1 Volume */ + { 0x00000702, 0x0000 }, /* R1794 (0x702) - AIF1TX1MIX Input 2 Source */ + { 0x00000703, 0x0080 }, /* R1795 (0x703) - AIF1TX1MIX Input 2 Volume */ + { 0x00000704, 0x0000 }, /* R1796 (0x704) - AIF1TX1MIX Input 3 Source */ + { 0x00000705, 0x0080 }, /* R1797 (0x705) - AIF1TX1MIX Input 3 Volume */ + { 0x00000706, 0x0000 }, /* R1798 (0x706) - AIF1TX1MIX Input 4 Source */ + { 0x00000707, 0x0080 }, /* R1799 (0x707) - AIF1TX1MIX Input 4 Volume */ + { 0x00000708, 0x0000 }, /* R1800 (0x708) - AIF1TX2MIX Input 1 Source */ + { 0x00000709, 0x0080 }, /* R1801 (0x709) - AIF1TX2MIX Input 1 Volume */ + { 0x0000070a, 0x0000 }, /* R1802 (0x70a) - AIF1TX2MIX Input 2 Source */ + { 0x0000070b, 0x0080 }, /* R1803 (0x70b) - AIF1TX2MIX Input 2 Volume */ + { 0x0000070c, 0x0000 }, /* R1804 (0x70c) - AIF1TX2MIX Input 3 Source */ + { 0x0000070d, 0x0080 }, /* R1805 (0x70d) - AIF1TX2MIX Input 3 Volume */ + { 0x0000070e, 0x0000 }, /* R1806 (0x70e) - AIF1TX2MIX Input 4 Source */ + { 0x0000070f, 0x0080 }, /* R1807 (0x70f) - AIF1TX2MIX Input 4 Volume */ + { 0x00000710, 0x0000 }, /* R1808 (0x710) - AIF1TX3MIX Input 1 Source */ + { 0x00000711, 0x0080 }, /* R1809 (0x711) - AIF1TX3MIX Input 1 Volume */ + { 0x00000712, 0x0000 }, /* R1810 (0x712) - AIF1TX3MIX Input 2 Source */ + { 0x00000713, 0x0080 }, /* R1811 (0x713) - AIF1TX3MIX Input 2 Volume */ + { 0x00000714, 0x0000 }, /* R1812 (0x714) - AIF1TX3MIX Input 3 Source */ + { 0x00000715, 0x0080 }, /* R1813 (0x715) - AIF1TX3MIX Input 3 Volume */ + { 0x00000716, 0x0000 }, /* R1814 (0x716) - AIF1TX3MIX Input 4 Source */ + { 0x00000717, 0x0080 }, /* R1815 (0x717) - AIF1TX3MIX Input 4 Volume */ + { 0x00000718, 0x0000 }, /* R1816 (0x718) - AIF1TX4MIX Input 1 Source */ + { 0x00000719, 0x0080 }, /* R1817 (0x719) - AIF1TX4MIX Input 1 Volume */ + { 0x0000071a, 0x0000 }, /* R1818 (0x71a) - AIF1TX4MIX Input 2 Source */ + { 0x0000071b, 0x0080 }, /* R1819 (0x71b) - AIF1TX4MIX Input 2 Volume */ + { 0x0000071c, 0x0000 }, /* R1820 (0x71c) - AIF1TX4MIX Input 3 Source */ + { 0x0000071d, 0x0080 }, /* R1821 (0x71d) - AIF1TX4MIX Input 3 Volume */ + { 0x0000071e, 0x0000 }, /* R1822 (0x71e) - AIF1TX4MIX Input 4 Source */ + { 0x0000071f, 0x0080 }, /* R1823 (0x71f) - AIF1TX4MIX Input 4 Volume */ + { 0x00000720, 0x0000 }, /* R1824 (0x720) - AIF1TX5MIX Input 1 Source */ + { 0x00000721, 0x0080 }, /* R1825 (0x721) - AIF1TX5MIX Input 1 Volume */ + { 0x00000722, 0x0000 }, /* R1826 (0x722) - AIF1TX5MIX Input 2 Source */ + { 0x00000723, 0x0080 }, /* R1827 (0x723) - AIF1TX5MIX Input 2 Volume */ + { 0x00000724, 0x0000 }, /* R1828 (0x724) - AIF1TX5MIX Input 3 Source */ + { 0x00000725, 0x0080 }, /* R1829 (0x725) - AIF1TX5MIX Input 3 Volume */ + { 0x00000726, 0x0000 }, /* R1830 (0x726) - AIF1TX5MIX Input 4 Source */ + { 0x00000727, 0x0080 }, /* R1831 (0x727) - AIF1TX5MIX Input 4 Volume */ + { 0x00000728, 0x0000 }, /* R1832 (0x728) - AIF1TX6MIX Input 1 Source */ + { 0x00000729, 0x0080 }, /* R1833 (0x729) - AIF1TX6MIX Input 1 Volume */ + { 0x0000072a, 0x0000 }, /* R1834 (0x72a) - AIF1TX6MIX Input 2 Source */ + { 0x0000072b, 0x0080 }, /* R1835 (0x72b) - AIF1TX6MIX Input 2 Volume */ + { 0x0000072c, 0x0000 }, /* R1836 (0x72c) - AIF1TX6MIX Input 3 Source */ + { 0x0000072d, 0x0080 }, /* R1837 (0x72d) - AIF1TX6MIX Input 3 Volume */ + { 0x0000072e, 0x0000 }, /* R1838 (0x72e) - AIF1TX6MIX Input 4 Source */ + { 0x0000072f, 0x0080 }, /* R1839 (0x72f) - AIF1TX6MIX Input 4 Volume */ + { 0x00000740, 0x0000 }, /* R1856 (0x740) - AIF2TX1MIX Input 1 Source */ + { 0x00000741, 0x0080 }, /* R1857 (0x741) - AIF2TX1MIX Input 1 Volume */ + { 0x00000742, 0x0000 }, /* R1858 (0x742) - AIF2TX1MIX Input 2 Source */ + { 0x00000743, 0x0080 }, /* R1859 (0x743) - AIF2TX1MIX Input 2 Volume */ + { 0x00000744, 0x0000 }, /* R1860 (0x744) - AIF2TX1MIX Input 3 Source */ + { 0x00000745, 0x0080 }, /* R1861 (0x745) - AIF2TX1MIX Input 3 Volume */ + { 0x00000746, 0x0000 }, /* R1862 (0x746) - AIF2TX1MIX Input 4 Source */ + { 0x00000747, 0x0080 }, /* R1863 (0x747) - AIF2TX1MIX Input 4 Volume */ + { 0x00000748, 0x0000 }, /* R1864 (0x748) - AIF2TX2MIX Input 1 Source */ + { 0x00000749, 0x0080 }, /* R1865 (0x749) - AIF2TX2MIX Input 1 Volume */ + { 0x0000074a, 0x0000 }, /* R1866 (0x74a) - AIF2TX2MIX Input 2 Source */ + { 0x0000074b, 0x0080 }, /* R1867 (0x74b) - AIF2TX2MIX Input 2 Volume */ + { 0x0000074c, 0x0000 }, /* R1868 (0x74c) - AIF2TX2MIX Input 3 Source */ + { 0x0000074d, 0x0080 }, /* R1869 (0x74d) - AIF2TX2MIX Input 3 Volume */ + { 0x0000074e, 0x0000 }, /* R1870 (0x74e) - AIF2TX2MIX Input 4 Source */ + { 0x0000074f, 0x0080 }, /* R1871 (0x74f) - AIF2TX2MIX Input 4 Volume */ + { 0x00000780, 0x0000 }, /* R1920 (0x780) - AIF3TX1MIX Input 1 Source */ + { 0x00000781, 0x0080 }, /* R1921 (0x781) - AIF3TX1MIX Input 1 Volume */ + { 0x00000782, 0x0000 }, /* R1922 (0x782) - AIF3TX1MIX Input 2 Source */ + { 0x00000783, 0x0080 }, /* R1923 (0x783) - AIF3TX1MIX Input 2 Volume */ + { 0x00000784, 0x0000 }, /* R1924 (0x784) - AIF3TX1MIX Input 3 Source */ + { 0x00000785, 0x0080 }, /* R1925 (0x785) - AIF3TX1MIX Input 3 Volume */ + { 0x00000786, 0x0000 }, /* R1926 (0x786) - AIF3TX1MIX Input 4 Source */ + { 0x00000787, 0x0080 }, /* R1927 (0x787) - AIF3TX1MIX Input 4 Volume */ + { 0x00000788, 0x0000 }, /* R1928 (0x788) - AIF3TX2MIX Input 1 Source */ + { 0x00000789, 0x0080 }, /* R1929 (0x789) - AIF3TX2MIX Input 1 Volume */ + { 0x0000078a, 0x0000 }, /* R1930 (0x78a) - AIF3TX2MIX Input 2 Source */ + { 0x0000078b, 0x0080 }, /* R1931 (0x78b) - AIF3TX2MIX Input 2 Volume */ + { 0x0000078c, 0x0000 }, /* R1932 (0x78c) - AIF3TX2MIX Input 3 Source */ + { 0x0000078d, 0x0080 }, /* R1933 (0x78d) - AIF3TX2MIX Input 3 Volume */ + { 0x0000078e, 0x0000 }, /* R1934 (0x78e) - AIF3TX2MIX Input 4 Source */ + { 0x0000078f, 0x0080 }, /* R1935 (0x78f) - AIF3TX2MIX Input 4 Volume */ + { 0x000007c0, 0x0000 }, /* R1984 (0x7c0) - SLIMTX1MIX Input 1 Source */ + { 0x000007c1, 0x0080 }, /* R1985 (0x7c1) - SLIMTX1MIX Input 1 Volume */ + { 0x000007c2, 0x0000 }, /* R1986 (0x7c2) - SLIMTX1MIX Input 2 Source */ + { 0x000007c3, 0x0080 }, /* R1987 (0x7c3) - SLIMTX1MIX Input 2 Volume */ + { 0x000007c4, 0x0000 }, /* R1988 (0x7c4) - SLIMTX1MIX Input 3 Source */ + { 0x000007c5, 0x0080 }, /* R1989 (0x7c5) - SLIMTX1MIX Input 3 Volume */ + { 0x000007c6, 0x0000 }, /* R1990 (0x7c6) - SLIMTX1MIX Input 4 Source */ + { 0x000007c7, 0x0080 }, /* R1991 (0x7c7) - SLIMTX1MIX Input 4 Volume */ + { 0x000007c8, 0x0000 }, /* R1992 (0x7c8) - SLIMTX2MIX Input 1 Source */ + { 0x000007c9, 0x0080 }, /* R1993 (0x7c9) - SLIMTX2MIX Input 1 Volume */ + { 0x000007ca, 0x0000 }, /* R1994 (0x7ca) - SLIMTX2MIX Input 2 Source */ + { 0x000007cb, 0x0080 }, /* R1995 (0x7cb) - SLIMTX2MIX Input 2 Volume */ + { 0x000007cc, 0x0000 }, /* R1996 (0x7cc) - SLIMTX2MIX Input 3 Source */ + { 0x000007cd, 0x0080 }, /* R1997 (0x7cd) - SLIMTX2MIX Input 3 Volume */ + { 0x000007ce, 0x0000 }, /* R1998 (0x7ce) - SLIMTX2MIX Input 4 Source */ + { 0x000007cf, 0x0080 }, /* R1999 (0x7cf) - SLIMTX2MIX Input 4 Volume */ + { 0x000007d0, 0x0000 }, /* R2000 (0x7d0) - SLIMTX3MIX Input 1 Source */ + { 0x000007d1, 0x0080 }, /* R2001 (0x7d1) - SLIMTX3MIX Input 1 Volume */ + { 0x000007d2, 0x0000 }, /* R2002 (0x7d2) - SLIMTX3MIX Input 2 Source */ + { 0x000007d3, 0x0080 }, /* R2003 (0x7d3) - SLIMTX3MIX Input 2 Volume */ + { 0x000007d4, 0x0000 }, /* R2004 (0x7d4) - SLIMTX3MIX Input 3 Source */ + { 0x000007d5, 0x0080 }, /* R2005 (0x7d5) - SLIMTX3MIX Input 3 Volume */ + { 0x000007d6, 0x0000 }, /* R2006 (0x7d6) - SLIMTX3MIX Input 4 Source */ + { 0x000007d7, 0x0080 }, /* R2007 (0x7d7) - SLIMTX3MIX Input 4 Volume */ + { 0x000007d8, 0x0000 }, /* R2008 (0x7d8) - SLIMTX4MIX Input 1 Source */ + { 0x000007d9, 0x0080 }, /* R2009 (0x7d9) - SLIMTX4MIX Input 1 Volume */ + { 0x000007da, 0x0000 }, /* R2010 (0x7da) - SLIMTX4MIX Input 2 Source */ + { 0x000007db, 0x0080 }, /* R2011 (0x7db) - SLIMTX4MIX Input 2 Volume */ + { 0x000007dc, 0x0000 }, /* R2012 (0x7dc) - SLIMTX4MIX Input 3 Source */ + { 0x000007dd, 0x0080 }, /* R2013 (0x7dd) - SLIMTX4MIX Input 3 Volume */ + { 0x000007de, 0x0000 }, /* R2014 (0x7de) - SLIMTX4MIX Input 4 Source */ + { 0x000007df, 0x0080 }, /* R2015 (0x7df) - SLIMTX4MIX Input 4 Volume */ + { 0x000007e0, 0x0000 }, /* R2016 (0x7e0) - SLIMTX5MIX Input 1 Source */ + { 0x000007e1, 0x0080 }, /* R2017 (0x7e1) - SLIMTX5MIX Input 1 Volume */ + { 0x000007e2, 0x0000 }, /* R2018 (0x7e2) - SLIMTX5MIX Input 2 Source */ + { 0x000007e3, 0x0080 }, /* R2019 (0x7e3) - SLIMTX5MIX Input 2 Volume */ + { 0x000007e4, 0x0000 }, /* R2020 (0x7e4) - SLIMTX5MIX Input 3 Source */ + { 0x000007e5, 0x0080 }, /* R2021 (0x7e5) - SLIMTX5MIX Input 3 Volume */ + { 0x000007e6, 0x0000 }, /* R2022 (0x7e6) - SLIMTX5MIX Input 4 Source */ + { 0x000007e7, 0x0080 }, /* R2023 (0x7e7) - SLIMTX5MIX Input 4 Volume */ + { 0x000007e8, 0x0000 }, /* R2024 (0x7e8) - SLIMTX6MIX Input 1 Source */ + { 0x000007e9, 0x0080 }, /* R2025 (0x7e9) - SLIMTX6MIX Input 1 Volume */ + { 0x000007ea, 0x0000 }, /* R2026 (0x7ea) - SLIMTX6MIX Input 2 Source */ + { 0x000007eb, 0x0080 }, /* R2027 (0x7eb) - SLIMTX6MIX Input 2 Volume */ + { 0x000007ec, 0x0000 }, /* R2028 (0x7ec) - SLIMTX6MIX Input 3 Source */ + { 0x000007ed, 0x0080 }, /* R2029 (0x7ed) - SLIMTX6MIX Input 3 Volume */ + { 0x000007ee, 0x0000 }, /* R2030 (0x7ee) - SLIMTX6MIX Input 4 Source */ + { 0x000007ef, 0x0080 }, /* R2031 (0x7ef) - SLIMTX6MIX Input 4 Volume */ + { 0x00000800, 0x0000 }, /* R2048 (0x800) - SPDIF1TX1MIX Input 1 Source*/ + { 0x00000801, 0x0080 }, /* R2049 (0x801) - SPDIF1TX1MIX Input 1 Volume*/ + { 0x00000808, 0x0000 }, /* R2056 (0x808) - SPDIF1TX2MIX Input 1 Source*/ + { 0x00000809, 0x0080 }, /* R2057 (0x809) - SPDIF1TX2MIX Input 1 Volume*/ + { 0x00000880, 0x0000 }, /* R2176 (0x880) - EQ1MIX Input 1 Source */ + { 0x00000881, 0x0080 }, /* R2177 (0x881) - EQ1MIX Input 1 Volume */ + { 0x00000882, 0x0000 }, /* R2178 (0x882) - EQ1MIX Input 2 Source */ + { 0x00000883, 0x0080 }, /* R2179 (0x883) - EQ1MIX Input 2 Volume */ + { 0x00000884, 0x0000 }, /* R2180 (0x884) - EQ1MIX Input 3 Source */ + { 0x00000885, 0x0080 }, /* R2181 (0x885) - EQ1MIX Input 3 Volume */ + { 0x00000886, 0x0000 }, /* R2182 (0x886) - EQ1MIX Input 4 Source */ + { 0x00000887, 0x0080 }, /* R2183 (0x887) - EQ1MIX Input 4 Volume */ + { 0x00000888, 0x0000 }, /* R2184 (0x888) - EQ2MIX Input 1 Source */ + { 0x00000889, 0x0080 }, /* R2185 (0x889) - EQ2MIX Input 1 Volume */ + { 0x0000088a, 0x0000 }, /* R2186 (0x88a) - EQ2MIX Input 2 Source */ + { 0x0000088b, 0x0080 }, /* R2187 (0x88b) - EQ2MIX Input 2 Volume */ + { 0x0000088c, 0x0000 }, /* R2188 (0x88c) - EQ2MIX Input 3 Source */ + { 0x0000088d, 0x0080 }, /* R2189 (0x88d) - EQ2MIX Input 3 Volume */ + { 0x0000088e, 0x0000 }, /* R2190 (0x88e) - EQ2MIX Input 4 Source */ + { 0x0000088f, 0x0080 }, /* R2191 (0x88f) - EQ2MIX Input 4 Volume */ + { 0x00000890, 0x0000 }, /* R2192 (0x890) - EQ3MIX Input 1 Source */ + { 0x00000891, 0x0080 }, /* R2193 (0x891) - EQ3MIX Input 1 Volume */ + { 0x00000892, 0x0000 }, /* R2194 (0x892) - EQ3MIX Input 2 Source */ + { 0x00000893, 0x0080 }, /* R2195 (0x893) - EQ3MIX Input 2 Volume */ + { 0x00000894, 0x0000 }, /* R2196 (0x894) - EQ3MIX Input 3 Source */ + { 0x00000895, 0x0080 }, /* R2197 (0x895) - EQ3MIX Input 3 Volume */ + { 0x00000896, 0x0000 }, /* R2198 (0x896) - EQ3MIX Input 4 Source */ + { 0x00000897, 0x0080 }, /* R2199 (0x897) - EQ3MIX Input 4 Volume */ + { 0x00000898, 0x0000 }, /* R2200 (0x898) - EQ4MIX Input 1 Source */ + { 0x00000899, 0x0080 }, /* R2201 (0x899) - EQ4MIX Input 1 Volume */ + { 0x0000089a, 0x0000 }, /* R2202 (0x89a) - EQ4MIX Input 2 Source */ + { 0x0000089b, 0x0080 }, /* R2203 (0x89b) - EQ4MIX Input 2 Volume */ + { 0x0000089c, 0x0000 }, /* R2204 (0x89c) - EQ4MIX Input 3 Source */ + { 0x0000089d, 0x0080 }, /* R2205 (0x89d) - EQ4MIX Input 3 Volume */ + { 0x0000089e, 0x0000 }, /* R2206 (0x89e) - EQ4MIX Input 4 Source */ + { 0x0000089f, 0x0080 }, /* R2207 (0x89f) - EQ4MIX Input 4 Volume */ + { 0x000008c0, 0x0000 }, /* R2240 (0x8c0) - DRC1LMIX Input 1 Source */ + { 0x000008c1, 0x0080 }, /* R2241 (0x8c1) - DRC1LMIX Input 1 Volume */ + { 0x000008c2, 0x0000 }, /* R2242 (0x8c2) - DRC1LMIX Input 2 Source */ + { 0x000008c3, 0x0080 }, /* R2243 (0x8c3) - DRC1LMIX Input 2 Volume */ + { 0x000008c4, 0x0000 }, /* R2244 (0x8c4) - DRC1LMIX Input 3 Source */ + { 0x000008c5, 0x0080 }, /* R2245 (0x8c5) - DRC1LMIX Input 3 Volume */ + { 0x000008c6, 0x0000 }, /* R2246 (0x8c6) - DRC1LMIX Input 4 Source */ + { 0x000008c7, 0x0080 }, /* R2247 (0x8c7) - DRC1LMIX Input 4 Volume */ + { 0x000008c8, 0x0000 }, /* R2248 (0x8c8) - DRC1RMIX Input 1 Source */ + { 0x000008c9, 0x0080 }, /* R2249 (0x8c9) - DRC1RMIX Input 1 Volume */ + { 0x000008ca, 0x0000 }, /* R2250 (0x8ca) - DRC1RMIX Input 2 Source */ + { 0x000008cb, 0x0080 }, /* R2251 (0x8cb) - DRC1RMIX Input 2 Volume */ + { 0x000008cc, 0x0000 }, /* R2252 (0x8cc) - DRC1RMIX Input 3 Source */ + { 0x000008cd, 0x0080 }, /* R2253 (0x8cd) - DRC1RMIX Input 3 Volume */ + { 0x000008ce, 0x0000 }, /* R2254 (0x8ce) - DRC1RMIX Input 4 Source */ + { 0x000008cf, 0x0080 }, /* R2255 (0x8cf) - DRC1RMIX Input 4 Volume */ + { 0x000008d0, 0x0000 }, /* R2256 (0x8d0) - DRC2LMIX Input 1 Source */ + { 0x000008d1, 0x0080 }, /* R2257 (0x8d1) - DRC2LMIX Input 1 Volume */ + { 0x000008d2, 0x0000 }, /* R2258 (0x8d2) - DRC2LMIX Input 2 Source */ + { 0x000008d3, 0x0080 }, /* R2259 (0x8d3) - DRC2LMIX Input 2 Volume */ + { 0x000008d4, 0x0000 }, /* R2260 (0x8d4) - DRC2LMIX Input 3 Source */ + { 0x000008d5, 0x0080 }, /* R2261 (0x8d5) - DRC2LMIX Input 3 Volume */ + { 0x000008d6, 0x0000 }, /* R2262 (0x8d6) - DRC2LMIX Input 4 Source */ + { 0x000008d7, 0x0080 }, /* R2263 (0x8d7) - DRC2LMIX Input 4 Volume */ + { 0x000008d8, 0x0000 }, /* R2264 (0x8d8) - DRC2RMIX Input 1 Source */ + { 0x000008d9, 0x0080 }, /* R2265 (0x8d9) - DRC2RMIX Input 1 Volume */ + { 0x000008da, 0x0000 }, /* R2266 (0x8da) - DRC2RMIX Input 2 Source */ + { 0x000008db, 0x0080 }, /* R2267 (0x8db) - DRC2RMIX Input 2 Volume */ + { 0x000008dc, 0x0000 }, /* R2268 (0x8dc) - DRC2RMIX Input 3 Source */ + { 0x000008dd, 0x0080 }, /* R2269 (0x8dd) - DRC2RMIX Input 3 Volume */ + { 0x000008de, 0x0000 }, /* R2270 (0x8de) - DRC2RMIX Input 4 Source */ + { 0x000008df, 0x0080 }, /* R2271 (0x8df) - DRC2RMIX Input 4 Volume */ + { 0x00000900, 0x0000 }, /* R2304 (0x900) - HPLP1MIX Input 1 Source */ + { 0x00000901, 0x0080 }, /* R2305 (0x901) - HPLP1MIX Input 1 Volume */ + { 0x00000902, 0x0000 }, /* R2306 (0x902) - HPLP1MIX Input 2 Source */ + { 0x00000903, 0x0080 }, /* R2307 (0x903) - HPLP1MIX Input 2 Volume */ + { 0x00000904, 0x0000 }, /* R2308 (0x904) - HPLP1MIX Input 3 Source */ + { 0x00000905, 0x0080 }, /* R2309 (0x905) - HPLP1MIX Input 3 Volume */ + { 0x00000906, 0x0000 }, /* R2310 (0x906) - HPLP1MIX Input 4 Source */ + { 0x00000907, 0x0080 }, /* R2311 (0x907) - HPLP1MIX Input 4 Volume */ + { 0x00000908, 0x0000 }, /* R2312 (0x908) - HPLP2MIX Input 1 Source */ + { 0x00000909, 0x0080 }, /* R2313 (0x909) - HPLP2MIX Input 1 Volume */ + { 0x0000090a, 0x0000 }, /* R2314 (0x90a) - HPLP2MIX Input 2 Source */ + { 0x0000090b, 0x0080 }, /* R2315 (0x90b) - HPLP2MIX Input 2 Volume */ + { 0x0000090c, 0x0000 }, /* R2316 (0x90c) - HPLP2MIX Input 3 Source */ + { 0x0000090d, 0x0080 }, /* R2317 (0x90d) - HPLP2MIX Input 3 Volume */ + { 0x0000090e, 0x0000 }, /* R2318 (0x90e) - HPLP2MIX Input 4 Source */ + { 0x0000090f, 0x0080 }, /* R2319 (0x90f) - HPLP2MIX Input 4 Volume */ + { 0x00000910, 0x0000 }, /* R2320 (0x910) - HPLP3MIX Input 1 Source */ + { 0x00000911, 0x0080 }, /* R2321 (0x911) - HPLP3MIX Input 1 Volume */ + { 0x00000912, 0x0000 }, /* R2322 (0x912) - HPLP3MIX Input 2 Source */ + { 0x00000913, 0x0080 }, /* R2323 (0x913) - HPLP3MIX Input 2 Volume */ + { 0x00000914, 0x0000 }, /* R2324 (0x914) - HPLP3MIX Input 3 Source */ + { 0x00000915, 0x0080 }, /* R2325 (0x915) - HPLP3MIX Input 3 Volume */ + { 0x00000916, 0x0000 }, /* R2326 (0x916) - HPLP3MIX Input 4 Source */ + { 0x00000917, 0x0080 }, /* R2327 (0x917) - HPLP3MIX Input 4 Volume */ + { 0x00000918, 0x0000 }, /* R2328 (0x918) - HPLP4MIX Input 1 Source */ + { 0x00000919, 0x0080 }, /* R2329 (0x919) - HPLP4MIX Input 1 Volume */ + { 0x0000091a, 0x0000 }, /* R2330 (0x91a) - HPLP4MIX Input 2 Source */ + { 0x0000091b, 0x0080 }, /* R2331 (0x91b) - HPLP4MIX Input 2 Volume */ + { 0x0000091c, 0x0000 }, /* R2332 (0x91c) - HPLP4MIX Input 3 Source */ + { 0x0000091d, 0x0080 }, /* R2333 (0x91d) - HPLP4MIX Input 3 Volume */ + { 0x0000091e, 0x0000 }, /* R2334 (0x91e) - HPLP4MIX Input 4 Source */ + { 0x0000091f, 0x0080 }, /* R2335 (0x91f) - HPLP4MIX Input 4 Volume */ + { 0x00000940, 0x0000 }, /* R2368 (0x940) - DSP1LMIX Input 1 Source */ + { 0x00000941, 0x0080 }, /* R2369 (0x941) - DSP1LMIX Input 1 Volume */ + { 0x00000942, 0x0000 }, /* R2370 (0x942) - DSP1LMIX Input 2 Source */ + { 0x00000943, 0x0080 }, /* R2371 (0x943) - DSP1LMIX Input 2 Volume */ + { 0x00000944, 0x0000 }, /* R2372 (0x944) - DSP1LMIX Input 3 Source */ + { 0x00000945, 0x0080 }, /* R2373 (0x945) - DSP1LMIX Input 3 Volume */ + { 0x00000946, 0x0000 }, /* R2374 (0x946) - DSP1LMIX Input 4 Source */ + { 0x00000947, 0x0080 }, /* R2375 (0x947) - DSP1LMIX Input 4 Volume */ + { 0x00000948, 0x0000 }, /* R2376 (0x948) - DSP1RMIX Input 1 Source */ + { 0x00000949, 0x0080 }, /* R2377 (0x949) - DSP1RMIX Input 1 Volume */ + { 0x0000094a, 0x0000 }, /* R2378 (0x94a) - DSP1RMIX Input 2 Source */ + { 0x0000094b, 0x0080 }, /* R2379 (0x94b) - DSP1RMIX Input 2 Volume */ + { 0x0000094c, 0x0000 }, /* R2380 (0x94c) - DSP1RMIX Input 3 Source */ + { 0x0000094d, 0x0080 }, /* R2381 (0x94d) - DSP1RMIX Input 3 Volume */ + { 0x0000094e, 0x0000 }, /* R2382 (0x94e) - DSP1RMIX Input 4 Source */ + { 0x0000094f, 0x0080 }, /* R2383 (0x94f) - DSP1RMIX Input 4 Volume */ + { 0x00000950, 0x0000 }, /* R2384 (0x950) - DSP1AUX1MIX Input 1 Source */ + { 0x00000958, 0x0000 }, /* R2392 (0x958) - DSP1AUX2MIX Input 1 Source */ + { 0x00000960, 0x0000 }, /* R2400 (0x960) - DSP1AUX3MIX Input 1 Source */ + { 0x00000968, 0x0000 }, /* R2408 (0x968) - DSP1AUX4MIX Input 1 Source */ + { 0x00000970, 0x0000 }, /* R2416 (0x970) - DSP1AUX5MIX Input 1 Source */ + { 0x00000978, 0x0000 }, /* R2424 (0x978) - DSP1AUX6MIX Input 1 Source */ + { 0x00000980, 0x0000 }, /* R2432 (0x980) - DSP2LMIX Input 1 Source */ + { 0x00000981, 0x0080 }, /* R2433 (0x981) - DSP2LMIX Input 1 Volume */ + { 0x00000982, 0x0000 }, /* R2434 (0x982) - DSP2LMIX Input 2 Source */ + { 0x00000983, 0x0080 }, /* R2435 (0x983) - DSP2LMIX Input 2 Volume */ + { 0x00000984, 0x0000 }, /* R2436 (0x984) - DSP2LMIX Input 3 Source */ + { 0x00000985, 0x0080 }, /* R2437 (0x985) - DSP2LMIX Input 3 Volume */ + { 0x00000986, 0x0000 }, /* R2438 (0x986) - DSP2LMIX Input 4 Source */ + { 0x00000987, 0x0080 }, /* R2439 (0x987) - DSP2LMIX Input 4 Volume */ + { 0x00000988, 0x0000 }, /* R2440 (0x988) - DSP2RMIX Input 1 Source */ + { 0x00000989, 0x0080 }, /* R2441 (0x989) - DSP2RMIX Input 1 Volume */ + { 0x0000098a, 0x0000 }, /* R2442 (0x98a) - DSP2RMIX Input 2 Source */ + { 0x0000098b, 0x0080 }, /* R2443 (0x98b) - DSP2RMIX Input 2 Volume */ + { 0x0000098c, 0x0000 }, /* R2444 (0x98c) - DSP2RMIX Input 3 Source */ + { 0x0000098d, 0x0080 }, /* R2445 (0x98d) - DSP2RMIX Input 3 Volume */ + { 0x0000098e, 0x0000 }, /* R2446 (0x98e) - DSP2RMIX Input 4 Source */ + { 0x0000098f, 0x0080 }, /* R2447 (0x98f) - DSP2RMIX Input 4 Volume */ + { 0x00000990, 0x0000 }, /* R2448 (0x990) - DSP2AUX1MIX Input 1 Source */ + { 0x00000998, 0x0000 }, /* R2456 (0x998) - DSP2AUX2MIX Input 1 Source */ + { 0x000009a0, 0x0000 }, /* R2464 (0x9a0) - DSP2AUX3MIX Input 1 Source */ + { 0x000009a8, 0x0000 }, /* R2472 (0x9a8) - DSP2AUX4MIX Input 1 Source */ + { 0x000009b0, 0x0000 }, /* R2480 (0x9b0) - DSP2AUX5MIX Input 1 Source */ + { 0x000009b8, 0x0000 }, /* R2488 (0x9b8) - DSP2AUX6MIX Input 1 Source */ + { 0x000009c0, 0x0000 }, /* R2496 (0x9c0) - DSP3LMIX Input 1 Source */ + { 0x000009c1, 0x0080 }, /* R2497 (0x9c1) - DSP3LMIX Input 1 Volume */ + { 0x000009c2, 0x0000 }, /* R2498 (0x9c2) - DSP3LMIX Input 2 Source */ + { 0x000009c3, 0x0080 }, /* R2499 (0x9c3) - DSP3LMIX Input 2 Volume */ + { 0x000009c4, 0x0000 }, /* R2500 (0x9c4) - DSP3LMIX Input 3 Source */ + { 0x000009c5, 0x0080 }, /* R2501 (0x9c5) - DSP3LMIX Input 3 Volume */ + { 0x000009c6, 0x0000 }, /* R2502 (0x9c6) - DSP3LMIX Input 4 Source */ + { 0x000009c7, 0x0080 }, /* R2503 (0x9c7) - DSP3LMIX Input 4 Volume */ + { 0x000009c8, 0x0000 }, /* R2504 (0x9c8) - DSP3RMIX Input 1 Source */ + { 0x000009c9, 0x0080 }, /* R2505 (0x9c9) - DSP3RMIX Input 1 Volume */ + { 0x000009ca, 0x0000 }, /* R2506 (0x9ca) - DSP3RMIX Input 2 Source */ + { 0x000009cb, 0x0080 }, /* R2507 (0x9cb) - DSP3RMIX Input 2 Volume */ + { 0x000009cc, 0x0000 }, /* R2508 (0x9cc) - DSP3RMIX Input 3 Source */ + { 0x000009cd, 0x0080 }, /* R2509 (0x9cd) - DSP3RMIX Input 3 Volume */ + { 0x000009ce, 0x0000 }, /* R2510 (0x9ce) - DSP3RMIX Input 4 Source */ + { 0x000009cf, 0x0080 }, /* R2511 (0x9cf) - DSP3RMIX Input 4 Volume */ + { 0x000009d0, 0x0000 }, /* R2512 (0x9d0) - DSP3AUX1MIX Input 1 Source */ + { 0x000009d8, 0x0000 }, /* R2520 (0x9d8) - DSP3AUX2MIX Input 1 Source */ + { 0x000009e0, 0x0000 }, /* R2528 (0x9e0) - DSP3AUX3MIX Input 1 Source */ + { 0x000009e8, 0x0000 }, /* R2536 (0x9e8) - DSP3AUX4MIX Input 1 Source */ + { 0x000009f0, 0x0000 }, /* R2544 (0x9f0) - DSP3AUX5MIX Input 1 Source */ + { 0x000009f8, 0x0000 }, /* R2552 (0x9f8) - DSP3AUX6MIX Input 1 Source */ + { 0x00000b00, 0x0000 }, /* R2816 (0xb00) - ISRC1DEC1MIX Input 1 Source*/ + { 0x00000b08, 0x0000 }, /* R2824 (0xb08) - ISRC1DEC2MIX Input 1 Source*/ + { 0x00000b10, 0x0000 }, /* R2832 (0xb10) - ISRC1DEC3MIX Input 1 Source*/ + { 0x00000b18, 0x0000 }, /* R2840 (0xb18) - ISRC1DEC4MIX Input 1 Source*/ + { 0x00000b20, 0x0000 }, /* R2848 (0xb20) - ISRC1INT1MIX Input 1 Source*/ + { 0x00000b28, 0x0000 }, /* R2856 (0xb28) - ISRC1INT2MIX Input 1 Source*/ + { 0x00000b30, 0x0000 }, /* R2864 (0xb30) - ISRC1INT3MIX Input 1 Source*/ + { 0x00000b38, 0x0000 }, /* R2872 (0xb38) - ISRC1INT4MIX Input 1 Source*/ + { 0x00000b40, 0x0000 }, /* R2880 (0xb40) - ISRC2DEC1MIX Input 1 Source*/ + { 0x00000b48, 0x0000 }, /* R2888 (0xb48) - ISRC2DEC2MIX Input 1 Source*/ + { 0x00000b50, 0x0000 }, /* R2896 (0xb50) - ISRC2DEC3MIX Input 1 Source*/ + { 0x00000b58, 0x0000 }, /* R2904 (0xb58) - ISRC2DEC4MIX Input 1 Source*/ + { 0x00000b60, 0x0000 }, /* R2912 (0xb60) - ISRC2INT1MIX Input 1 Source*/ + { 0x00000b68, 0x0000 }, /* R2920 (0xb68) - ISRC2INT2MIX Input 1 Source*/ + { 0x00000b70, 0x0000 }, /* R2928 (0xb70) - ISRC2INT3MIX Input 1 Source*/ + { 0x00000b78, 0x0000 }, /* R2936 (0xb78) - ISRC2INT4MIX Input 1 Source*/ + { 0x00000e00, 0x0000 }, /* R3584 (0xe00) - FX Ctrl1 */ + { 0x00000e10, 0x6318 }, /* R3600 (0xe10) - EQ1_1 */ + { 0x00000e11, 0x6300 }, /* R3601 (0xe11) - EQ1_2 */ + { 0x00000e12, 0x0fc8 }, /* R3602 (0xe12) - EQ1_3 */ + { 0x00000e13, 0x03fe }, /* R3603 (0xe13) - EQ1_4 */ + { 0x00000e14, 0x00e0 }, /* R3604 (0xe14) - EQ1_5 */ + { 0x00000e15, 0x1ec4 }, /* R3605 (0xe15) - EQ1_6 */ + { 0x00000e16, 0xf136 }, /* R3606 (0xe16) - EQ1_7 */ + { 0x00000e17, 0x0409 }, /* R3607 (0xe17) - EQ1_8 */ + { 0x00000e18, 0x04cc }, /* R3608 (0xe18) - EQ1_9 */ + { 0x00000e19, 0x1c9b }, /* R3609 (0xe19) - EQ1_10 */ + { 0x00000e1a, 0xf337 }, /* R3610 (0xe1a) - EQ1_11 */ + { 0x00000e1b, 0x040b }, /* R3611 (0xe1b) - EQ1_12 */ + { 0x00000e1c, 0x0cbb }, /* R3612 (0xe1c) - EQ1_13 */ + { 0x00000e1d, 0x16f8 }, /* R3613 (0xe1d) - EQ1_14 */ + { 0x00000e1e, 0xf7d9 }, /* R3614 (0xe1e) - EQ1_15 */ + { 0x00000e1f, 0x040a }, /* R3615 (0xe1f) - EQ1_16 */ + { 0x00000e20, 0x1f14 }, /* R3616 (0xe20) - EQ1_17 */ + { 0x00000e21, 0x058c }, /* R3617 (0xe21) - EQ1_18 */ + { 0x00000e22, 0x0563 }, /* R3618 (0xe22) - EQ1_19 */ + { 0x00000e23, 0x4000 }, /* R3619 (0xe23) - EQ1_20 */ + { 0x00000e24, 0x0b75 }, /* R3620 (0xe24) - EQ1_21 */ + { 0x00000e26, 0x6318 }, /* R3622 (0xe26) - EQ2_1 */ + { 0x00000e27, 0x6300 }, /* R3623 (0xe27) - EQ2_2 */ + { 0x00000e28, 0x0fc8 }, /* R3624 (0xe28) - EQ2_3 */ + { 0x00000e29, 0x03fe }, /* R3625 (0xe29) - EQ2_4 */ + { 0x00000e2a, 0x00e0 }, /* R3626 (0xe2a) - EQ2_5 */ + { 0x00000e2b, 0x1ec4 }, /* R3627 (0xe2b) - EQ2_6 */ + { 0x00000e2c, 0xf136 }, /* R3628 (0xe2c) - EQ2_7 */ + { 0x00000e2d, 0x0409 }, /* R3629 (0xe2d) - EQ2_8 */ + { 0x00000e2e, 0x04cc }, /* R3630 (0xe2e) - EQ2_9 */ + { 0x00000e2f, 0x1c9b }, /* R3631 (0xe2f) - EQ2_10 */ + { 0x00000e30, 0xf337 }, /* R3632 (0xe30) - EQ2_11 */ + { 0x00000e31, 0x040b }, /* R3633 (0xe31) - EQ2_12 */ + { 0x00000e32, 0x0cbb }, /* R3634 (0xe32) - EQ2_13 */ + { 0x00000e33, 0x16f8 }, /* R3635 (0xe33) - EQ2_14 */ + { 0x00000e34, 0xf7d9 }, /* R3636 (0xe34) - EQ2_15 */ + { 0x00000e35, 0x040a }, /* R3637 (0xe35) - EQ2_16 */ + { 0x00000e36, 0x1f14 }, /* R3638 (0xe36) - EQ2_17 */ + { 0x00000e37, 0x058c }, /* R3639 (0xe37) - EQ2_18 */ + { 0x00000e38, 0x0563 }, /* R3640 (0xe38) - EQ2_19 */ + { 0x00000e39, 0x4000 }, /* R3641 (0xe39) - EQ2_20 */ + { 0x00000e3a, 0x0b75 }, /* R3642 (0xe3a) - EQ2_21 */ + { 0x00000e3c, 0x6318 }, /* R3644 (0xe3c) - EQ3_1 */ + { 0x00000e3d, 0x6300 }, /* R3645 (0xe3d) - EQ3_2 */ + { 0x00000e3e, 0x0fc8 }, /* R3646 (0xe3e) - EQ3_3 */ + { 0x00000e3f, 0x03fe }, /* R3647 (0xe3f) - EQ3_4 */ + { 0x00000e40, 0x00e0 }, /* R3648 (0xe40) - EQ3_5 */ + { 0x00000e41, 0x1ec4 }, /* R3649 (0xe41) - EQ3_6 */ + { 0x00000e42, 0xf136 }, /* R3650 (0xe42) - EQ3_7 */ + { 0x00000e43, 0x0409 }, /* R3651 (0xe43) - EQ3_8 */ + { 0x00000e44, 0x04cc }, /* R3652 (0xe44) - EQ3_9 */ + { 0x00000e45, 0x1c9b }, /* R3653 (0xe45) - EQ3_10 */ + { 0x00000e46, 0xf337 }, /* R3654 (0xe46) - EQ3_11 */ + { 0x00000e47, 0x040b }, /* R3655 (0xe47) - EQ3_12 */ + { 0x00000e48, 0x0cbb }, /* R3656 (0xe48) - EQ3_13 */ + { 0x00000e49, 0x16f8 }, /* R3657 (0xe49) - EQ3_14 */ + { 0x00000e4a, 0xf7d9 }, /* R3658 (0xe4a) - EQ3_15 */ + { 0x00000e4b, 0x040a }, /* R3659 (0xe4b) - EQ3_16 */ + { 0x00000e4c, 0x1f14 }, /* R3660 (0xe4c) - EQ3_17 */ + { 0x00000e4d, 0x058c }, /* R3661 (0xe4d) - EQ3_18 */ + { 0x00000e4e, 0x0563 }, /* R3662 (0xe4e) - EQ3_19 */ + { 0x00000e4f, 0x4000 }, /* R3663 (0xe4f) - EQ3_20 */ + { 0x00000e50, 0x0b75 }, /* R3664 (0xe50) - EQ3_21 */ + { 0x00000e52, 0x6318 }, /* R3666 (0xe52) - EQ4_1 */ + { 0x00000e53, 0x6300 }, /* R3667 (0xe53) - EQ4_2 */ + { 0x00000e54, 0x0fc8 }, /* R3668 (0xe54) - EQ4_3 */ + { 0x00000e55, 0x03fe }, /* R3669 (0xe55) - EQ4_4 */ + { 0x00000e56, 0x00e0 }, /* R3670 (0xe56) - EQ4_5 */ + { 0x00000e57, 0x1ec4 }, /* R3671 (0xe57) - EQ4_6 */ + { 0x00000e58, 0xf136 }, /* R3672 (0xe58) - EQ4_7 */ + { 0x00000e59, 0x0409 }, /* R3673 (0xe59) - EQ4_8 */ + { 0x00000e5a, 0x04cc }, /* R3674 (0xe5a) - EQ4_9 */ + { 0x00000e5b, 0x1c9b }, /* R3675 (0xe5b) - EQ4_10 */ + { 0x00000e5c, 0xf337 }, /* R3676 (0xe5c) - EQ4_11 */ + { 0x00000e5d, 0x040b }, /* R3677 (0xe5d) - EQ4_12 */ + { 0x00000e5e, 0x0cbb }, /* R3678 (0xe5e) - EQ4_13 */ + { 0x00000e5f, 0x16f8 }, /* R3679 (0xe5f) - EQ4_14 */ + { 0x00000e60, 0xf7d9 }, /* R3680 (0xe60) - EQ4_15 */ + { 0x00000e61, 0x040a }, /* R3681 (0xe61) - EQ4_16 */ + { 0x00000e62, 0x1f14 }, /* R3682 (0xe62) - EQ4_17 */ + { 0x00000e63, 0x058c }, /* R3683 (0xe63) - EQ4_18 */ + { 0x00000e64, 0x0563 }, /* R3684 (0xe64) - EQ4_19 */ + { 0x00000e65, 0x4000 }, /* R3685 (0xe65) - EQ4_20 */ + { 0x00000e66, 0x0b75 }, /* R3686 (0xe66) - EQ4_21 */ + { 0x00000e80, 0x0018 }, /* R3712 (0xe80) - DRC1 ctrl1 */ + { 0x00000e81, 0x0933 }, /* R3713 (0xe81) - DRC1 ctrl2 */ + { 0x00000e82, 0x0018 }, /* R3714 (0xe82) - DRC1 ctrl3 */ + { 0x00000e83, 0x0000 }, /* R3715 (0xe83) - DRC1 ctrl4 */ + { 0x00000e84, 0x0000 }, /* R3716 (0xe84) - DRC1 ctrl5 */ + { 0x00000e88, 0x0018 }, /* R3720 (0xe88) - DRC2 ctrl1 */ + { 0x00000e89, 0x0933 }, /* R3721 (0xe89) - DRC2 ctrl2 */ + { 0x00000e8a, 0x0018 }, /* R3722 (0xe8a) - DRC2 ctrl3 */ + { 0x00000e8b, 0x0000 }, /* R3723 (0xe8b) - DRC2 ctrl4 */ + { 0x00000e8c, 0x0000 }, /* R3724 (0xe8c) - DRC2 ctrl5 */ + { 0x00000ec0, 0x0000 }, /* R3776 (0xec0) - HPLPF1_1 */ + { 0x00000ec1, 0x0000 }, /* R3777 (0xec1) - HPLPF1_2 */ + { 0x00000ec4, 0x0000 }, /* R3780 (0xec4) - HPLPF2_1 */ + { 0x00000ec5, 0x0000 }, /* R3781 (0xec5) - HPLPF2_2 */ + { 0x00000ec8, 0x0000 }, /* R3784 (0xec8) - HPLPF3_1 */ + { 0x00000ec9, 0x0000 }, /* R3785 (0xec9) - HPLPF3_2 */ + { 0x00000ecc, 0x0000 }, /* R3788 (0xecc) - HPLPF4_1 */ + { 0x00000ecd, 0x0000 }, /* R3789 (0xecd) - HPLPF4_2 */ + { 0x00000ef0, 0x0000 }, /* R3824 (0xef0) - ISRC 1 CTRL 1 */ + { 0x00000ef1, 0x0001 }, /* R3825 (0xef1) - ISRC 1 CTRL 2 */ + { 0x00000ef2, 0x0000 }, /* R3826 (0xef2) - ISRC 1 CTRL 3 */ + { 0x00000ef3, 0x0000 }, /* R3827 (0xef3) - ISRC 2 CTRL 1 */ + { 0x00000ef4, 0x0001 }, /* R3828 (0xef4) - ISRC 2 CTRL 2 */ + { 0x00000ef5, 0x0000 }, /* R3829 (0xef5) - ISRC 2 CTRL 3 */ + { 0x00001300, 0x0000 }, /* R4864 (0x1300) - DAC Comp 1 */ + { 0x00001302, 0x0000 }, /* R4866 (0x1302) - DAC Comp 2 */ + { 0x00001380, 0x0000 }, /* R4992 (0x1380) - FRF Coefficient 1L 1 */ + { 0x00001381, 0x0000 }, /* R4993 (0x1381) - FRF Coefficient 1L 2 */ + { 0x00001382, 0x0000 }, /* R4994 (0x1382) - FRF Coefficient 1L 3 */ + { 0x00001383, 0x0000 }, /* R4995 (0x1383) - FRF Coefficient 1L 4 */ + { 0x00001390, 0x0000 }, /* R5008 (0x1390) - FRF Coefficient 1R 1 */ + { 0x00001391, 0x0000 }, /* R5009 (0x1391) - FRF Coefficient 1R 2 */ + { 0x00001392, 0x0000 }, /* R5010 (0x1392) - FRF Coefficient 1R 3 */ + { 0x00001393, 0x0000 }, /* R5011 (0x1393) - FRF Coefficient 1R 4 */ + { 0x000013a0, 0x0000 }, /* R5024 (0x13a0) - FRF Coefficient 4L 1 */ + { 0x000013a1, 0x0000 }, /* R5025 (0x13a1) - FRF Coefficient 4L 2 */ + { 0x000013a2, 0x0000 }, /* R5026 (0x13a2) - FRF Coefficient 4L 3 */ + { 0x000013a3, 0x0000 }, /* R5027 (0x13a3) - FRF Coefficient 4L 4 */ + { 0x000013b0, 0x0000 }, /* R5040 (0x13b0) - FRF Coefficient 5L 1 */ + { 0x000013b1, 0x0000 }, /* R5041 (0x13b1) - FRF Coefficient 5L 2 */ + { 0x000013b2, 0x0000 }, /* R5042 (0x13b2) - FRF Coefficient 5L 3 */ + { 0x000013b3, 0x0000 }, /* R5043 (0x13b3) - FRF Coefficient 5L 4 */ + { 0x000013c0, 0x0000 }, /* R5040 (0x13c0) - FRF Coefficient 5R 1 */ + { 0x000013c1, 0x0000 }, /* R5041 (0x13c1) - FRF Coefficient 5R 2 */ + { 0x000013c2, 0x0000 }, /* R5042 (0x13c2) - FRF Coefficient 5R 3 */ + { 0x000013c3, 0x0000 }, /* R5043 (0x13c3) - FRF Coefficient 5R 4 */ + { 0x00001700, 0x2001 }, /* R5888 (0x1700) - GPIO1 Control 1 */ + { 0x00001701, 0xf000 }, /* R5889 (0x1701) - GPIO1 Control 2 */ + { 0x00001702, 0x2001 }, /* R5890 (0x1702) - GPIO2 Control 1 */ + { 0x00001703, 0xf000 }, /* R5891 (0x1703) - GPIO2 Control 2 */ + { 0x00001704, 0x2001 }, /* R5892 (0x1704) - GPIO3 Control 1 */ + { 0x00001705, 0xf000 }, /* R5893 (0x1705) - GPIO3 Control 2 */ + { 0x00001706, 0x2001 }, /* R5894 (0x1706) - GPIO4 Control 1 */ + { 0x00001707, 0xf000 }, /* R5895 (0x1707) - GPIO4 Control 2 */ + { 0x00001708, 0x2001 }, /* R5896 (0x1708) - GPIO5 Control 1 */ + { 0x00001709, 0xf000 }, /* R5897 (0x1709) - GPIO5 Control 2 */ + { 0x0000170a, 0x2001 }, /* R5898 (0x170a) - GPIO6 Control 1 */ + { 0x0000170b, 0xf000 }, /* R5899 (0x170b) - GPIO6 Control 2 */ + { 0x0000170c, 0x2001 }, /* R5900 (0x170c) - GPIO7 Control 1 */ + { 0x0000170d, 0xf000 }, /* R5901 (0x170d) - GPIO7 Control 2 */ + { 0x0000170e, 0x2001 }, /* R5902 (0x170e) - GPIO8 Control 1 */ + { 0x0000170f, 0xf000 }, /* R5903 (0x170f) - GPIO8 Control 2 */ + { 0x00001710, 0x2001 }, /* R5904 (0x1710) - GPIO9 Control 1 */ + { 0x00001711, 0xf000 }, /* R5905 (0x1711) - GPIO9 Control 2 */ + { 0x00001712, 0x2001 }, /* R5906 (0x1712) - GPIO10 Control 1 */ + { 0x00001713, 0xf000 }, /* R5907 (0x1713) - GPIO10 Control 2 */ + { 0x00001714, 0x2001 }, /* R5908 (0x1714) - GPIO11 Control 1 */ + { 0x00001715, 0xf000 }, /* R5909 (0x1715) - GPIO11 Control 2 */ + { 0x00001716, 0x2001 }, /* R5910 (0x1716) - GPIO12 Control 1 */ + { 0x00001717, 0xf000 }, /* R5911 (0x1717) - GPIO12 Control 2 */ + { 0x00001718, 0x2001 }, /* R5912 (0x1718) - GPIO13 Control 1 */ + { 0x00001719, 0xf000 }, /* R5913 (0x1719) - GPIO13 Control 2 */ + { 0x0000171a, 0x2001 }, /* R5914 (0x171a) - GPIO14 Control 1 */ + { 0x0000171b, 0xf000 }, /* R5915 (0x171b) - GPIO14 Control 2 */ + { 0x0000171c, 0x2001 }, /* R5916 (0x171c) - GPIO15 Control 1 */ + { 0x0000171d, 0xf000 }, /* R5917 (0x171d) - GPIO15 Control 2 */ + { 0x0000171e, 0x2001 }, /* R5918 (0x171e) - GPIO16 Control 1 */ + { 0x0000171f, 0xf000 }, /* R5919 (0x171f) - GPIO16 Control 2 */ + { 0x00001840, 0xffff }, /* R6208 (0x1840) - IRQ1 Mask 1 */ + { 0x00001841, 0xffff }, /* R6209 (0x1841) - IRQ1 Mask 2 */ + { 0x00001842, 0xffff }, /* R6210 (0x1842) - IRQ1 Mask 3 */ + { 0x00001843, 0xffff }, /* R6211 (0x1843) - IRQ1 Mask 4 */ + { 0x00001844, 0xffff }, /* R6212 (0x1844) - IRQ1 Mask 5 */ + { 0x00001845, 0xffff }, /* R6213 (0x1845) - IRQ1 Mask 6 */ + { 0x00001846, 0xffff }, /* R6214 (0x1846) - IRQ1 Mask 7 */ + { 0x00001847, 0xffff }, /* R6215 (0x1847) - IRQ1 Mask 8 */ + { 0x00001848, 0xffff }, /* R6216 (0x1848) - IRQ1 Mask 9 */ + { 0x00001849, 0xffff }, /* R6217 (0x1849) - IRQ1 Mask 10 */ + { 0x0000184a, 0xffff }, /* R6218 (0x184a) - IRQ1 Mask 11 */ + { 0x0000184b, 0xffff }, /* R6219 (0x184b) - IRQ1 Mask 12 */ + { 0x0000184c, 0xffff }, /* R6220 (0x184c) - IRQ1 Mask 13 */ + { 0x0000184d, 0xffff }, /* R6221 (0x184d) - IRQ1 Mask 14 */ + { 0x0000184e, 0xffff }, /* R6222 (0x184e) - IRQ1 Mask 15 */ + { 0x0000184f, 0xffff }, /* R6223 (0x184f) - IRQ1 Mask 16 */ + { 0x00001850, 0xffff }, /* R6224 (0x1850) - IRQ1 Mask 17 */ + { 0x00001851, 0xffff }, /* R6225 (0x1851) - IRQ1 Mask 18 */ + { 0x00001852, 0xffff }, /* R6226 (0x1852) - IRQ1 Mask 19 */ + { 0x00001853, 0xffff }, /* R6227 (0x1853) - IRQ1 Mask 20 */ + { 0x00001854, 0xffff }, /* R6228 (0x1854) - IRQ1 Mask 21 */ + { 0x00001855, 0xffff }, /* R6229 (0x1855) - IRQ1 Mask 22 */ + { 0x00001856, 0xffff }, /* R6230 (0x1856) - IRQ1 Mask 23 */ + { 0x00001857, 0xffff }, /* R6231 (0x1857) - IRQ1 Mask 24 */ + { 0x00001858, 0xffff }, /* R6232 (0x1858) - IRQ1 Mask 25 */ + { 0x00001859, 0xffff }, /* R6233 (0x1859) - IRQ1 Mask 26 */ + { 0x0000185a, 0xffff }, /* R6234 (0x185a) - IRQ1 Mask 27 */ + { 0x0000185b, 0xffff }, /* R6235 (0x185b) - IRQ1 Mask 28 */ + { 0x0000185c, 0xffff }, /* R6236 (0x185c) - IRQ1 Mask 29 */ + { 0x0000185d, 0xffff }, /* R6237 (0x185d) - IRQ1 Mask 30 */ + { 0x0000185e, 0xffff }, /* R6238 (0x185e) - IRQ1 Mask 31 */ + { 0x0000185f, 0xffff }, /* R6239 (0x185f) - IRQ1 Mask 32 */ + { 0x00001860, 0xffff }, /* R6240 (0x1860) - IRQ1 Mask 33 */ + { 0x00001a06, 0x0000 }, /* R6662 (0x1a06) - Interrupt Debounce 7 */ + { 0x00001a80, 0x4400 }, /* R6784 (0x1a80) - IRQ1 CTRL */ +}; + +static bool cs47l35_is_adsp_memory(unsigned int reg) +{ + switch (reg) { + case 0x080000 ... 0x085ffe: + case 0x0a0000 ... 0x0a7ffe: + case 0x0c0000 ... 0x0c1ffe: + case 0x0e0000 ... 0x0e1ffe: + case 0x100000 ... 0x10effe: + case 0x120000 ... 0x12bffe: + case 0x136000 ... 0x137ffe: + case 0x140000 ... 0x14bffe: + case 0x160000 ... 0x161ffe: + case 0x180000 ... 0x18effe: + case 0x1a0000 ... 0x1b1ffe: + case 0x1b6000 ... 0x1b7ffe: + case 0x1c0000 ... 0x1cbffe: + case 0x1e0000 ... 0x1e1ffe: + return true; + default: + return false; + } +} + +static bool cs47l35_16bit_readable_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_SOFTWARE_RESET: + case MADERA_HARDWARE_REVISION: + case MADERA_WRITE_SEQUENCER_CTRL_0: + case MADERA_WRITE_SEQUENCER_CTRL_1: + case MADERA_WRITE_SEQUENCER_CTRL_2: + case MADERA_TONE_GENERATOR_1: + case MADERA_TONE_GENERATOR_2: + case MADERA_TONE_GENERATOR_3: + case MADERA_TONE_GENERATOR_4: + case MADERA_TONE_GENERATOR_5: + case MADERA_PWM_DRIVE_1: + case MADERA_PWM_DRIVE_2: + case MADERA_PWM_DRIVE_3: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_1: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_2: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_3: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_4: + case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1: + case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: + case MADERA_HAPTICS_CONTROL_1: + case MADERA_HAPTICS_CONTROL_2: + case MADERA_HAPTICS_PHASE_1_INTENSITY: + case MADERA_HAPTICS_PHASE_1_DURATION: + case MADERA_HAPTICS_PHASE_2_INTENSITY: + case MADERA_HAPTICS_PHASE_2_DURATION: + case MADERA_HAPTICS_PHASE_3_INTENSITY: + case MADERA_HAPTICS_PHASE_3_DURATION: + case MADERA_HAPTICS_STATUS: + case MADERA_COMFORT_NOISE_GENERATOR: + case MADERA_CLOCK_32K_1: + case MADERA_SYSTEM_CLOCK_1: + case MADERA_SAMPLE_RATE_1: + case MADERA_SAMPLE_RATE_2: + case MADERA_SAMPLE_RATE_3: + case MADERA_SAMPLE_RATE_1_STATUS: + case MADERA_SAMPLE_RATE_2_STATUS: + case MADERA_SAMPLE_RATE_3_STATUS: + case MADERA_DSP_CLOCK_1: + case MADERA_DSP_CLOCK_2: + case MADERA_OUTPUT_SYSTEM_CLOCK: + case MADERA_OUTPUT_ASYNC_CLOCK: + case MADERA_RATE_ESTIMATOR_1: + case MADERA_RATE_ESTIMATOR_2: + case MADERA_RATE_ESTIMATOR_3: + case MADERA_RATE_ESTIMATOR_4: + case MADERA_RATE_ESTIMATOR_5: + case MADERA_FLL1_CONTROL_1: + case MADERA_FLL1_CONTROL_2: + case MADERA_FLL1_CONTROL_3: + case MADERA_FLL1_CONTROL_4: + case MADERA_FLL1_CONTROL_5: + case MADERA_FLL1_CONTROL_6: + case MADERA_FLL1_CONTROL_7: + case MADERA_FLL1_EFS_2: + case MADERA_FLL1_LOOP_FILTER_TEST_1: + case CS47L35_FLL1_SYNCHRONISER_1: + case CS47L35_FLL1_SYNCHRONISER_2: + case CS47L35_FLL1_SYNCHRONISER_3: + case CS47L35_FLL1_SYNCHRONISER_4: + case CS47L35_FLL1_SYNCHRONISER_5: + case CS47L35_FLL1_SYNCHRONISER_6: + case CS47L35_FLL1_SYNCHRONISER_7: + case CS47L35_FLL1_SPREAD_SPECTRUM: + case CS47L35_FLL1_GPIO_CLOCK: + case MADERA_MIC_CHARGE_PUMP_1: + case MADERA_HP_CHARGE_PUMP_8: + case MADERA_LDO2_CONTROL_1: + case MADERA_MIC_BIAS_CTRL_1: + case MADERA_MIC_BIAS_CTRL_2: + case MADERA_MIC_BIAS_CTRL_5: + case MADERA_MIC_BIAS_CTRL_6: + case MADERA_HP_CTRL_1L: + case MADERA_HP_CTRL_1R: + case MADERA_DCS_HP1L_CONTROL: + case MADERA_DCS_HP1R_CONTROL: + case MADERA_EDRE_HP_STEREO_CONTROL: + case MADERA_ACCESSORY_DETECT_MODE_1: + case MADERA_HEADPHONE_DETECT_1: + case MADERA_HEADPHONE_DETECT_2: + case MADERA_HEADPHONE_DETECT_3: + case MADERA_HEADPHONE_DETECT_5: + case MADERA_MICD_CLAMP_CONTROL: + case MADERA_MIC_DETECT_1_CONTROL_1: + case MADERA_MIC_DETECT_1_CONTROL_2: + case MADERA_MIC_DETECT_1_CONTROL_3: + case MADERA_MIC_DETECT_1_LEVEL_1: + case MADERA_MIC_DETECT_1_LEVEL_2: + case MADERA_MIC_DETECT_1_LEVEL_3: + case MADERA_MIC_DETECT_1_LEVEL_4: + case MADERA_MIC_DETECT_1_CONTROL_4: + case MADERA_GP_SWITCH_1: + case MADERA_JACK_DETECT_ANALOGUE: + case MADERA_INPUT_ENABLES: + case MADERA_INPUT_ENABLES_STATUS: + case MADERA_INPUT_RATE: + case MADERA_INPUT_VOLUME_RAMP: + case MADERA_HPF_CONTROL: + case MADERA_IN1L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_1L: + case MADERA_DMIC1L_CONTROL: + case MADERA_IN1R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_1R: + case MADERA_DMIC1R_CONTROL: + case MADERA_IN2L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_2L: + case MADERA_DMIC2L_CONTROL: + case MADERA_IN2R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_2R: + case MADERA_DMIC2R_CONTROL: + case MADERA_OUTPUT_ENABLES_1: + case MADERA_OUTPUT_STATUS_1: + case MADERA_RAW_OUTPUT_STATUS_1: + case MADERA_OUTPUT_RATE_1: + case MADERA_OUTPUT_VOLUME_RAMP: + case MADERA_OUTPUT_PATH_CONFIG_1L: + case MADERA_DAC_DIGITAL_VOLUME_1L: + case MADERA_NOISE_GATE_SELECT_1L: + case MADERA_OUTPUT_PATH_CONFIG_1R: + case MADERA_DAC_DIGITAL_VOLUME_1R: + case MADERA_NOISE_GATE_SELECT_1R: + case MADERA_OUTPUT_PATH_CONFIG_4L: + case MADERA_DAC_DIGITAL_VOLUME_4L: + case MADERA_NOISE_GATE_SELECT_4L: + case MADERA_OUTPUT_PATH_CONFIG_5L: + case MADERA_DAC_DIGITAL_VOLUME_5L: + case MADERA_NOISE_GATE_SELECT_5L: + case MADERA_OUTPUT_PATH_CONFIG_5R: + case MADERA_DAC_DIGITAL_VOLUME_5R: + case MADERA_NOISE_GATE_SELECT_5R: + case MADERA_DRE_ENABLE: + case MADERA_EDRE_ENABLE: + case MADERA_EDRE_MANUAL: + case MADERA_DAC_AEC_CONTROL_1: + case MADERA_NOISE_GATE_CONTROL: + case MADERA_PDM_SPK1_CTRL_1: + case MADERA_PDM_SPK1_CTRL_2: + case MADERA_HP1_SHORT_CIRCUIT_CTRL: + case MADERA_HP_TEST_CTRL_5: + case MADERA_HP_TEST_CTRL_6: + case MADERA_AIF1_BCLK_CTRL: + case MADERA_AIF1_TX_PIN_CTRL: + case MADERA_AIF1_RX_PIN_CTRL: + case MADERA_AIF1_RATE_CTRL: + case MADERA_AIF1_FORMAT: + case MADERA_AIF1_RX_BCLK_RATE: + case MADERA_AIF1_FRAME_CTRL_1: + case MADERA_AIF1_FRAME_CTRL_2: + case MADERA_AIF1_FRAME_CTRL_3: + case MADERA_AIF1_FRAME_CTRL_4: + case MADERA_AIF1_FRAME_CTRL_5: + case MADERA_AIF1_FRAME_CTRL_6: + case MADERA_AIF1_FRAME_CTRL_7: + case MADERA_AIF1_FRAME_CTRL_8: + case MADERA_AIF1_FRAME_CTRL_11: + case MADERA_AIF1_FRAME_CTRL_12: + case MADERA_AIF1_FRAME_CTRL_13: + case MADERA_AIF1_FRAME_CTRL_14: + case MADERA_AIF1_FRAME_CTRL_15: + case MADERA_AIF1_FRAME_CTRL_16: + case MADERA_AIF1_TX_ENABLES: + case MADERA_AIF1_RX_ENABLES: + case MADERA_AIF2_BCLK_CTRL: + case MADERA_AIF2_TX_PIN_CTRL: + case MADERA_AIF2_RX_PIN_CTRL: + case MADERA_AIF2_RATE_CTRL: + case MADERA_AIF2_FORMAT: + case MADERA_AIF2_RX_BCLK_RATE: + case MADERA_AIF2_FRAME_CTRL_1: + case MADERA_AIF2_FRAME_CTRL_2: + case MADERA_AIF2_FRAME_CTRL_3: + case MADERA_AIF2_FRAME_CTRL_4: + case MADERA_AIF2_FRAME_CTRL_11: + case MADERA_AIF2_FRAME_CTRL_12: + case MADERA_AIF2_TX_ENABLES: + case MADERA_AIF2_RX_ENABLES: + case MADERA_AIF3_BCLK_CTRL: + case MADERA_AIF3_TX_PIN_CTRL: + case MADERA_AIF3_RX_PIN_CTRL: + case MADERA_AIF3_RATE_CTRL: + case MADERA_AIF3_FORMAT: + case MADERA_AIF3_RX_BCLK_RATE: + case MADERA_AIF3_FRAME_CTRL_1: + case MADERA_AIF3_FRAME_CTRL_2: + case MADERA_AIF3_FRAME_CTRL_3: + case MADERA_AIF3_FRAME_CTRL_4: + case MADERA_AIF3_FRAME_CTRL_11: + case MADERA_AIF3_FRAME_CTRL_12: + case MADERA_AIF3_TX_ENABLES: + case MADERA_AIF3_RX_ENABLES: + case MADERA_SPD1_TX_CONTROL: + case MADERA_SPD1_TX_CHANNEL_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_2: + case MADERA_SPD1_TX_CHANNEL_STATUS_3: + case MADERA_SLIMBUS_FRAMER_REF_GEAR: + case MADERA_SLIMBUS_RATES_1: + case MADERA_SLIMBUS_RATES_2: + case MADERA_SLIMBUS_RATES_3: + case MADERA_SLIMBUS_RATES_5: + case MADERA_SLIMBUS_RATES_6: + case MADERA_SLIMBUS_RATES_7: + case MADERA_SLIMBUS_RX_CHANNEL_ENABLE: + case MADERA_SLIMBUS_TX_CHANNEL_ENABLE: + case MADERA_SLIMBUS_RX_PORT_STATUS: + case MADERA_SLIMBUS_TX_PORT_STATUS: + case MADERA_PWM1MIX_INPUT_1_SOURCE: + case MADERA_PWM1MIX_INPUT_1_VOLUME: + case MADERA_PWM1MIX_INPUT_2_SOURCE: + case MADERA_PWM1MIX_INPUT_2_VOLUME: + case MADERA_PWM1MIX_INPUT_3_SOURCE: + case MADERA_PWM1MIX_INPUT_3_VOLUME: + case MADERA_PWM1MIX_INPUT_4_SOURCE: + case MADERA_PWM1MIX_INPUT_4_VOLUME: + case MADERA_PWM2MIX_INPUT_1_SOURCE: + case MADERA_PWM2MIX_INPUT_1_VOLUME: + case MADERA_PWM2MIX_INPUT_2_SOURCE: + case MADERA_PWM2MIX_INPUT_2_VOLUME: + case MADERA_PWM2MIX_INPUT_3_SOURCE: + case MADERA_PWM2MIX_INPUT_3_VOLUME: + case MADERA_PWM2MIX_INPUT_4_SOURCE: + case MADERA_PWM2MIX_INPUT_4_VOLUME: + case MADERA_OUT1LMIX_INPUT_1_SOURCE: + case MADERA_OUT1LMIX_INPUT_1_VOLUME: + case MADERA_OUT1LMIX_INPUT_2_SOURCE: + case MADERA_OUT1LMIX_INPUT_2_VOLUME: + case MADERA_OUT1LMIX_INPUT_3_SOURCE: + case MADERA_OUT1LMIX_INPUT_3_VOLUME: + case MADERA_OUT1LMIX_INPUT_4_SOURCE: + case MADERA_OUT1LMIX_INPUT_4_VOLUME: + case MADERA_OUT1RMIX_INPUT_1_SOURCE: + case MADERA_OUT1RMIX_INPUT_1_VOLUME: + case MADERA_OUT1RMIX_INPUT_2_SOURCE: + case MADERA_OUT1RMIX_INPUT_2_VOLUME: + case MADERA_OUT1RMIX_INPUT_3_SOURCE: + case MADERA_OUT1RMIX_INPUT_3_VOLUME: + case MADERA_OUT1RMIX_INPUT_4_SOURCE: + case MADERA_OUT1RMIX_INPUT_4_VOLUME: + case MADERA_OUT4LMIX_INPUT_1_SOURCE: + case MADERA_OUT4LMIX_INPUT_1_VOLUME: + case MADERA_OUT4LMIX_INPUT_2_SOURCE: + case MADERA_OUT4LMIX_INPUT_2_VOLUME: + case MADERA_OUT4LMIX_INPUT_3_SOURCE: + case MADERA_OUT4LMIX_INPUT_3_VOLUME: + case MADERA_OUT4LMIX_INPUT_4_SOURCE: + case MADERA_OUT4LMIX_INPUT_4_VOLUME: + case MADERA_OUT5LMIX_INPUT_1_SOURCE: + case MADERA_OUT5LMIX_INPUT_1_VOLUME: + case MADERA_OUT5LMIX_INPUT_2_SOURCE: + case MADERA_OUT5LMIX_INPUT_2_VOLUME: + case MADERA_OUT5LMIX_INPUT_3_SOURCE: + case MADERA_OUT5LMIX_INPUT_3_VOLUME: + case MADERA_OUT5LMIX_INPUT_4_SOURCE: + case MADERA_OUT5LMIX_INPUT_4_VOLUME: + case MADERA_OUT5RMIX_INPUT_1_SOURCE: + case MADERA_OUT5RMIX_INPUT_1_VOLUME: + case MADERA_OUT5RMIX_INPUT_2_SOURCE: + case MADERA_OUT5RMIX_INPUT_2_VOLUME: + case MADERA_OUT5RMIX_INPUT_3_SOURCE: + case MADERA_OUT5RMIX_INPUT_3_VOLUME: + case MADERA_OUT5RMIX_INPUT_4_SOURCE: + case MADERA_OUT5RMIX_INPUT_4_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_4_VOLUME: + case MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE: + case MADERA_SPDIF1TX1MIX_INPUT_1_VOLUME: + case MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE: + case MADERA_SPDIF1TX2MIX_INPUT_1_VOLUME: + case MADERA_EQ1MIX_INPUT_1_SOURCE: + case MADERA_EQ1MIX_INPUT_1_VOLUME: + case MADERA_EQ1MIX_INPUT_2_SOURCE: + case MADERA_EQ1MIX_INPUT_2_VOLUME: + case MADERA_EQ1MIX_INPUT_3_SOURCE: + case MADERA_EQ1MIX_INPUT_3_VOLUME: + case MADERA_EQ1MIX_INPUT_4_SOURCE: + case MADERA_EQ1MIX_INPUT_4_VOLUME: + case MADERA_EQ2MIX_INPUT_1_SOURCE: + case MADERA_EQ2MIX_INPUT_1_VOLUME: + case MADERA_EQ2MIX_INPUT_2_SOURCE: + case MADERA_EQ2MIX_INPUT_2_VOLUME: + case MADERA_EQ2MIX_INPUT_3_SOURCE: + case MADERA_EQ2MIX_INPUT_3_VOLUME: + case MADERA_EQ2MIX_INPUT_4_SOURCE: + case MADERA_EQ2MIX_INPUT_4_VOLUME: + case MADERA_EQ3MIX_INPUT_1_SOURCE: + case MADERA_EQ3MIX_INPUT_1_VOLUME: + case MADERA_EQ3MIX_INPUT_2_SOURCE: + case MADERA_EQ3MIX_INPUT_2_VOLUME: + case MADERA_EQ3MIX_INPUT_3_SOURCE: + case MADERA_EQ3MIX_INPUT_3_VOLUME: + case MADERA_EQ3MIX_INPUT_4_SOURCE: + case MADERA_EQ3MIX_INPUT_4_VOLUME: + case MADERA_EQ4MIX_INPUT_1_SOURCE: + case MADERA_EQ4MIX_INPUT_1_VOLUME: + case MADERA_EQ4MIX_INPUT_2_SOURCE: + case MADERA_EQ4MIX_INPUT_2_VOLUME: + case MADERA_EQ4MIX_INPUT_3_SOURCE: + case MADERA_EQ4MIX_INPUT_3_VOLUME: + case MADERA_EQ4MIX_INPUT_4_SOURCE: + case MADERA_EQ4MIX_INPUT_4_VOLUME: + case MADERA_DRC1LMIX_INPUT_1_SOURCE: + case MADERA_DRC1LMIX_INPUT_1_VOLUME: + case MADERA_DRC1LMIX_INPUT_2_SOURCE: + case MADERA_DRC1LMIX_INPUT_2_VOLUME: + case MADERA_DRC1LMIX_INPUT_3_SOURCE: + case MADERA_DRC1LMIX_INPUT_3_VOLUME: + case MADERA_DRC1LMIX_INPUT_4_SOURCE: + case MADERA_DRC1LMIX_INPUT_4_VOLUME: + case MADERA_DRC1RMIX_INPUT_1_SOURCE: + case MADERA_DRC1RMIX_INPUT_1_VOLUME: + case MADERA_DRC1RMIX_INPUT_2_SOURCE: + case MADERA_DRC1RMIX_INPUT_2_VOLUME: + case MADERA_DRC1RMIX_INPUT_3_SOURCE: + case MADERA_DRC1RMIX_INPUT_3_VOLUME: + case MADERA_DRC1RMIX_INPUT_4_SOURCE: + case MADERA_DRC1RMIX_INPUT_4_VOLUME: + case MADERA_DRC2LMIX_INPUT_1_SOURCE: + case MADERA_DRC2LMIX_INPUT_1_VOLUME: + case MADERA_DRC2LMIX_INPUT_2_SOURCE: + case MADERA_DRC2LMIX_INPUT_2_VOLUME: + case MADERA_DRC2LMIX_INPUT_3_SOURCE: + case MADERA_DRC2LMIX_INPUT_3_VOLUME: + case MADERA_DRC2LMIX_INPUT_4_SOURCE: + case MADERA_DRC2LMIX_INPUT_4_VOLUME: + case MADERA_DRC2RMIX_INPUT_1_SOURCE: + case MADERA_DRC2RMIX_INPUT_1_VOLUME: + case MADERA_DRC2RMIX_INPUT_2_SOURCE: + case MADERA_DRC2RMIX_INPUT_2_VOLUME: + case MADERA_DRC2RMIX_INPUT_3_SOURCE: + case MADERA_DRC2RMIX_INPUT_3_VOLUME: + case MADERA_DRC2RMIX_INPUT_4_SOURCE: + case MADERA_DRC2RMIX_INPUT_4_VOLUME: + case MADERA_HPLP1MIX_INPUT_1_SOURCE: + case MADERA_HPLP1MIX_INPUT_1_VOLUME: + case MADERA_HPLP1MIX_INPUT_2_SOURCE: + case MADERA_HPLP1MIX_INPUT_2_VOLUME: + case MADERA_HPLP1MIX_INPUT_3_SOURCE: + case MADERA_HPLP1MIX_INPUT_3_VOLUME: + case MADERA_HPLP1MIX_INPUT_4_SOURCE: + case MADERA_HPLP1MIX_INPUT_4_VOLUME: + case MADERA_HPLP2MIX_INPUT_1_SOURCE: + case MADERA_HPLP2MIX_INPUT_1_VOLUME: + case MADERA_HPLP2MIX_INPUT_2_SOURCE: + case MADERA_HPLP2MIX_INPUT_2_VOLUME: + case MADERA_HPLP2MIX_INPUT_3_SOURCE: + case MADERA_HPLP2MIX_INPUT_3_VOLUME: + case MADERA_HPLP2MIX_INPUT_4_SOURCE: + case MADERA_HPLP2MIX_INPUT_4_VOLUME: + case MADERA_HPLP3MIX_INPUT_1_SOURCE: + case MADERA_HPLP3MIX_INPUT_1_VOLUME: + case MADERA_HPLP3MIX_INPUT_2_SOURCE: + case MADERA_HPLP3MIX_INPUT_2_VOLUME: + case MADERA_HPLP3MIX_INPUT_3_SOURCE: + case MADERA_HPLP3MIX_INPUT_3_VOLUME: + case MADERA_HPLP3MIX_INPUT_4_SOURCE: + case MADERA_HPLP3MIX_INPUT_4_VOLUME: + case MADERA_HPLP4MIX_INPUT_1_SOURCE: + case MADERA_HPLP4MIX_INPUT_1_VOLUME: + case MADERA_HPLP4MIX_INPUT_2_SOURCE: + case MADERA_HPLP4MIX_INPUT_2_VOLUME: + case MADERA_HPLP4MIX_INPUT_3_SOURCE: + case MADERA_HPLP4MIX_INPUT_3_VOLUME: + case MADERA_HPLP4MIX_INPUT_4_SOURCE: + case MADERA_HPLP4MIX_INPUT_4_VOLUME: + case MADERA_DSP1LMIX_INPUT_1_SOURCE: + case MADERA_DSP1LMIX_INPUT_1_VOLUME: + case MADERA_DSP1LMIX_INPUT_2_SOURCE: + case MADERA_DSP1LMIX_INPUT_2_VOLUME: + case MADERA_DSP1LMIX_INPUT_3_SOURCE: + case MADERA_DSP1LMIX_INPUT_3_VOLUME: + case MADERA_DSP1LMIX_INPUT_4_SOURCE: + case MADERA_DSP1LMIX_INPUT_4_VOLUME: + case MADERA_DSP1RMIX_INPUT_1_SOURCE: + case MADERA_DSP1RMIX_INPUT_1_VOLUME: + case MADERA_DSP1RMIX_INPUT_2_SOURCE: + case MADERA_DSP1RMIX_INPUT_2_VOLUME: + case MADERA_DSP1RMIX_INPUT_3_SOURCE: + case MADERA_DSP1RMIX_INPUT_3_VOLUME: + case MADERA_DSP1RMIX_INPUT_4_SOURCE: + case MADERA_DSP1RMIX_INPUT_4_VOLUME: + case MADERA_DSP1AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP2LMIX_INPUT_1_SOURCE: + case MADERA_DSP2LMIX_INPUT_1_VOLUME: + case MADERA_DSP2LMIX_INPUT_2_SOURCE: + case MADERA_DSP2LMIX_INPUT_2_VOLUME: + case MADERA_DSP2LMIX_INPUT_3_SOURCE: + case MADERA_DSP2LMIX_INPUT_3_VOLUME: + case MADERA_DSP2LMIX_INPUT_4_SOURCE: + case MADERA_DSP2LMIX_INPUT_4_VOLUME: + case MADERA_DSP2RMIX_INPUT_1_SOURCE: + case MADERA_DSP2RMIX_INPUT_1_VOLUME: + case MADERA_DSP2RMIX_INPUT_2_SOURCE: + case MADERA_DSP2RMIX_INPUT_2_VOLUME: + case MADERA_DSP2RMIX_INPUT_3_SOURCE: + case MADERA_DSP2RMIX_INPUT_3_VOLUME: + case MADERA_DSP2RMIX_INPUT_4_SOURCE: + case MADERA_DSP2RMIX_INPUT_4_VOLUME: + case MADERA_DSP2AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP3LMIX_INPUT_1_SOURCE: + case MADERA_DSP3LMIX_INPUT_1_VOLUME: + case MADERA_DSP3LMIX_INPUT_2_SOURCE: + case MADERA_DSP3LMIX_INPUT_2_VOLUME: + case MADERA_DSP3LMIX_INPUT_3_SOURCE: + case MADERA_DSP3LMIX_INPUT_3_VOLUME: + case MADERA_DSP3LMIX_INPUT_4_SOURCE: + case MADERA_DSP3LMIX_INPUT_4_VOLUME: + case MADERA_DSP3RMIX_INPUT_1_SOURCE: + case MADERA_DSP3RMIX_INPUT_1_VOLUME: + case MADERA_DSP3RMIX_INPUT_2_SOURCE: + case MADERA_DSP3RMIX_INPUT_2_VOLUME: + case MADERA_DSP3RMIX_INPUT_3_SOURCE: + case MADERA_DSP3RMIX_INPUT_3_VOLUME: + case MADERA_DSP3RMIX_INPUT_4_SOURCE: + case MADERA_DSP3RMIX_INPUT_4_VOLUME: + case MADERA_DSP3AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX6MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC3MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC4MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT3MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT4MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC3MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC4MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT3MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT4MIX_INPUT_1_SOURCE: + case MADERA_FX_CTRL1: + case MADERA_FX_CTRL2: + case MADERA_EQ1_1 ... MADERA_EQ1_21: + case MADERA_EQ2_1 ... MADERA_EQ2_21: + case MADERA_EQ3_1 ... MADERA_EQ3_21: + case MADERA_EQ4_1 ... MADERA_EQ4_21: + case MADERA_DRC1_CTRL1: + case MADERA_DRC1_CTRL2: + case MADERA_DRC1_CTRL3: + case MADERA_DRC1_CTRL4: + case MADERA_DRC1_CTRL5: + case MADERA_DRC2_CTRL1: + case MADERA_DRC2_CTRL2: + case MADERA_DRC2_CTRL3: + case MADERA_DRC2_CTRL4: + case MADERA_DRC2_CTRL5: + case MADERA_HPLPF1_1: + case MADERA_HPLPF1_2: + case MADERA_HPLPF2_1: + case MADERA_HPLPF2_2: + case MADERA_HPLPF3_1: + case MADERA_HPLPF3_2: + case MADERA_HPLPF4_1: + case MADERA_HPLPF4_2: + case MADERA_ISRC_1_CTRL_1: + case MADERA_ISRC_1_CTRL_2: + case MADERA_ISRC_1_CTRL_3: + case MADERA_ISRC_2_CTRL_1: + case MADERA_ISRC_2_CTRL_2: + case MADERA_ISRC_2_CTRL_3: + case MADERA_DAC_COMP_1: + case MADERA_DAC_COMP_2: + case MADERA_FRF_COEFFICIENT_1L_1: + case MADERA_FRF_COEFFICIENT_1L_2: + case MADERA_FRF_COEFFICIENT_1L_3: + case MADERA_FRF_COEFFICIENT_1L_4: + case MADERA_FRF_COEFFICIENT_1R_1: + case MADERA_FRF_COEFFICIENT_1R_2: + case MADERA_FRF_COEFFICIENT_1R_3: + case MADERA_FRF_COEFFICIENT_1R_4: + case CS47L35_FRF_COEFFICIENT_4L_1: + case CS47L35_FRF_COEFFICIENT_4L_2: + case CS47L35_FRF_COEFFICIENT_4L_3: + case CS47L35_FRF_COEFFICIENT_4L_4: + case CS47L35_FRF_COEFFICIENT_5L_1: + case CS47L35_FRF_COEFFICIENT_5L_2: + case CS47L35_FRF_COEFFICIENT_5L_3: + case CS47L35_FRF_COEFFICIENT_5L_4: + case CS47L35_FRF_COEFFICIENT_5R_1: + case CS47L35_FRF_COEFFICIENT_5R_2: + case CS47L35_FRF_COEFFICIENT_5R_3: + case CS47L35_FRF_COEFFICIENT_5R_4: + case MADERA_GPIO1_CTRL_1 ... MADERA_GPIO16_CTRL_2: + case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33: + case MADERA_IRQ1_MASK_1 ... MADERA_IRQ1_MASK_33: + case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33: + case MADERA_INTERRUPT_DEBOUNCE_7: + case MADERA_IRQ1_CTRL: + return true; + default: + return false; + } +} + +static bool cs47l35_16bit_volatile_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_SOFTWARE_RESET: + case MADERA_HARDWARE_REVISION: + case MADERA_WRITE_SEQUENCER_CTRL_0: + case MADERA_WRITE_SEQUENCER_CTRL_1: + case MADERA_WRITE_SEQUENCER_CTRL_2: + case MADERA_HAPTICS_STATUS: + case MADERA_SAMPLE_RATE_1_STATUS: + case MADERA_SAMPLE_RATE_2_STATUS: + case MADERA_SAMPLE_RATE_3_STATUS: + case MADERA_HP_CTRL_1L: + case MADERA_HP_CTRL_1R: + case MADERA_DCS_HP1L_CONTROL: + case MADERA_DCS_HP1R_CONTROL: + case MADERA_MIC_DETECT_1_CONTROL_3: + case MADERA_MIC_DETECT_1_CONTROL_4: + case MADERA_HEADPHONE_DETECT_2: + case MADERA_HEADPHONE_DETECT_3: + case MADERA_HEADPHONE_DETECT_5: + case MADERA_INPUT_ENABLES_STATUS: + case MADERA_OUTPUT_STATUS_1: + case MADERA_RAW_OUTPUT_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_2: + case MADERA_SPD1_TX_CHANNEL_STATUS_3: + case MADERA_SLIMBUS_RX_PORT_STATUS: + case MADERA_SLIMBUS_TX_PORT_STATUS: + case MADERA_FX_CTRL2: + case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33: + case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33: + return true; + default: + return false; + } +} + +static bool cs47l35_32bit_readable_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_252: + case CS47L35_OTP_HPDET_CAL_1 ... CS47L35_OTP_HPDET_CAL_2: + case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_SCRATCH_2: + case MADERA_DSP2_CONFIG_1 ... MADERA_DSP2_SCRATCH_2: + case MADERA_DSP3_CONFIG_1 ... MADERA_DSP3_SCRATCH_2: + return true; + default: + return cs47l35_is_adsp_memory(reg); + } +} + +static bool cs47l35_32bit_volatile_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_252: + case CS47L35_OTP_HPDET_CAL_1 ... CS47L35_OTP_HPDET_CAL_2: + case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_SCRATCH_2: + case MADERA_DSP2_CONFIG_1 ... MADERA_DSP2_SCRATCH_2: + case MADERA_DSP3_CONFIG_1 ... MADERA_DSP3_SCRATCH_2: + return true; + default: + return cs47l35_is_adsp_memory(reg); + } +} + +const struct regmap_config cs47l35_16bit_spi_regmap = { + .name = "cs47l35_16bit", + .reg_bits = 32, + .pad_bits = 16, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = 0x1b00, + .readable_reg = cs47l35_16bit_readable_register, + .volatile_reg = cs47l35_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = cs47l35_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs47l35_reg_default), +}; +EXPORT_SYMBOL_GPL(cs47l35_16bit_spi_regmap); + +const struct regmap_config cs47l35_16bit_i2c_regmap = { + .name = "cs47l35_16bit", + .reg_bits = 32, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = 0x1b00, + .readable_reg = cs47l35_16bit_readable_register, + .volatile_reg = cs47l35_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = cs47l35_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs47l35_reg_default), +}; +EXPORT_SYMBOL_GPL(cs47l35_16bit_i2c_regmap); + +const struct regmap_config cs47l35_32bit_spi_regmap = { + .name = "cs47l35_32bit", + .reg_bits = 32, + .reg_stride = 2, + .pad_bits = 16, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_DSP3_SCRATCH_2, + .readable_reg = cs47l35_32bit_readable_register, + .volatile_reg = cs47l35_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs47l35_32bit_spi_regmap); + +const struct regmap_config cs47l35_32bit_i2c_regmap = { + .name = "cs47l35_32bit", + .reg_bits = 32, + .reg_stride = 2, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_DSP3_SCRATCH_2, + .readable_reg = cs47l35_32bit_readable_register, + .volatile_reg = cs47l35_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs47l35_32bit_i2c_regmap); diff --git a/drivers/mfd/cs47l85-tables.c b/drivers/mfd/cs47l85-tables.c new file mode 100644 index 000000000000..43803145d8e5 --- /dev/null +++ b/drivers/mfd/cs47l85-tables.c @@ -0,0 +1,3009 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Regmap tables for CS47L85 codec + * + * Copyright (C) 2015-2017 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/registers.h> + +#include "madera.h" + +static const struct reg_sequence cs47l85_reva_16_patch[] = { + { 0x80, 0x0003 }, + { 0x213, 0x03E4 }, + { 0x177, 0x0281 }, + { 0x197, 0x0281 }, + { 0x1B7, 0x0281 }, + { 0x4B1, 0x010A }, + { 0x4CF, 0x0933 }, + { 0x36C, 0x011B }, + { 0x4B8, 0x1120 }, + { 0x4A0, 0x3280 }, + { 0x4A1, 0x3200 }, + { 0x4A2, 0x3200 }, + { 0x441, 0xC050 }, + { 0x4A4, 0x000B }, + { 0x4A5, 0x000B }, + { 0x4A6, 0x000B }, + { 0x4E2, 0x1E1D }, + { 0x4E3, 0x1E1D }, + { 0x4E4, 0x1E1D }, + { 0x293, 0x0080 }, + { 0x17D, 0x0303 }, + { 0x19D, 0x0303 }, + { 0x27E, 0x0000 }, + { 0x80, 0x0000 }, + { 0x80, 0x0000 }, + { 0x448, 0x003f }, +}; + +static const struct reg_sequence cs47l85_revc_16_patch[] = { + { 0x27E, 0x0000 }, + { 0x2C2, 0x0005 }, + { 0x448, 0x003f }, +}; + +static const struct reg_sequence cs47l85_reva_32_patch[] = { + { 0x3000, 0xC2253632 }, + { 0x3002, 0xC2300001 }, + { 0x3004, 0x8225100E }, + { 0x3006, 0x22251803 }, + { 0x3008, 0x82310B00 }, + { 0x300A, 0xE231023B }, + { 0x300C, 0x02313B01 }, + { 0x300E, 0x62300000 }, + { 0x3010, 0xE2314288 }, + { 0x3012, 0x02310B00 }, + { 0x3014, 0x02310B00 }, + { 0x3016, 0x04050100 }, + { 0x3018, 0x42310C02 }, + { 0x301A, 0xE2310227 }, + { 0x301C, 0x02313B01 }, + { 0x301E, 0xE2314266 }, + { 0x3020, 0xE2315294 }, + { 0x3022, 0x02310B00 }, + { 0x3024, 0x02310B00 }, + { 0x3026, 0x02251100 }, + { 0x3028, 0x02251401 }, + { 0x302A, 0x02250200 }, + { 0x302C, 0x02251001 }, + { 0x302E, 0x02250200 }, + { 0x3030, 0xE2310266 }, + { 0x3032, 0x82314B15 }, + { 0x3034, 0x82310B15 }, + { 0x3036, 0xE2315294 }, + { 0x3038, 0x02310B00 }, + { 0x303A, 0x8225160D }, + { 0x303C, 0x0225F501 }, + { 0x303E, 0x8225061C }, + { 0x3040, 0x02251000 }, + { 0x3042, 0x04051101 }, + { 0x3044, 0x02251800 }, + { 0x3046, 0x42251203 }, + { 0x3048, 0x02251101 }, + { 0x304A, 0xC2251300 }, + { 0x304C, 0x2225FB02 }, + { 0x3050, 0xC2263632 }, + { 0x3052, 0xC2300001 }, + { 0x3054, 0x8226100E }, + { 0x3056, 0x22261803 }, + { 0x3058, 0x82310B02 }, + { 0x305A, 0xE231023B }, + { 0x305C, 0x02313B01 }, + { 0x305E, 0x62300000 }, + { 0x3060, 0xE2314288 }, + { 0x3062, 0x02310B00 }, + { 0x3064, 0x02310B00 }, + { 0x3066, 0x04050000 }, + { 0x3068, 0x42310C03 }, + { 0x306A, 0xE2310227 }, + { 0x306C, 0x02313B01 }, + { 0x306E, 0xE2314266 }, + { 0x3070, 0xE2315294 }, + { 0x3072, 0x02310B00 }, + { 0x3074, 0x02310B00 }, + { 0x3076, 0x02261100 }, + { 0x3078, 0x02261401 }, + { 0x307A, 0x02260200 }, + { 0x307C, 0x02261001 }, + { 0x307E, 0x02260200 }, + { 0x3080, 0xE2310266 }, + { 0x3082, 0x82314B17 }, + { 0x3084, 0x82310B17 }, + { 0x3086, 0xE2315294 }, + { 0x3088, 0x02310B00 }, + { 0x308A, 0x8226160D }, + { 0x308C, 0x0226F501 }, + { 0x308E, 0x8226061C }, + { 0x3090, 0x02261000 }, + { 0x3092, 0x04051101 }, + { 0x3094, 0x02261800 }, + { 0x3096, 0x42261203 }, + { 0x3098, 0x02261101 }, + { 0x309A, 0xC2261300 }, + { 0x309C, 0x2226FB02 }, + { 0x309E, 0x0000F000 }, + { 0x30A0, 0xC2273632 }, + { 0x30A2, 0xC2400001 }, + { 0x30A4, 0x8227100E }, + { 0x30A6, 0x22271803 }, + { 0x30A8, 0x82410B00 }, + { 0x30AA, 0xE241023B }, + { 0x30AC, 0x02413B01 }, + { 0x30AE, 0x62400000 }, + { 0x30B0, 0xE2414288 }, + { 0x30B2, 0x02410B00 }, + { 0x30B4, 0x02410B00 }, + { 0x30B6, 0x04050300 }, + { 0x30B8, 0x42410C02 }, + { 0x30BA, 0xE2410227 }, + { 0x30BC, 0x02413B01 }, + { 0x30BE, 0xE2414266 }, + { 0x30C0, 0xE2415294 }, + { 0x30C2, 0x02410B00 }, + { 0x30C4, 0x02410B00 }, + { 0x30C6, 0x02271100 }, + { 0x30C8, 0x02271401 }, + { 0x30CA, 0x02270200 }, + { 0x30CC, 0x02271001 }, + { 0x30CE, 0x02270200 }, + { 0x30D0, 0xE2410266 }, + { 0x30D2, 0x82414B15 }, + { 0x30D4, 0x82410B15 }, + { 0x30D6, 0xE2415294 }, + { 0x30D8, 0x02410B00 }, + { 0x30DA, 0x8227160D }, + { 0x30DC, 0x0227F501 }, + { 0x30DE, 0x8227061C }, + { 0x30E0, 0x02271000 }, + { 0x30E2, 0x04051101 }, + { 0x30E4, 0x02271800 }, + { 0x30E6, 0x42271203 }, + { 0x30E8, 0x02271101 }, + { 0x30EA, 0xC2271300 }, + { 0x30EC, 0x2227FB02 }, + { 0x30F0, 0xC2283632 }, + { 0x30F2, 0xC2400001 }, + { 0x30F4, 0x8228100E }, + { 0x30F6, 0x22281803 }, + { 0x30F8, 0x82410B02 }, + { 0x30FA, 0xE241023B }, + { 0x30FC, 0x02413B01 }, + { 0x30FE, 0x62400000 }, + { 0x3100, 0xE2414288 }, + { 0x3102, 0x02410B00 }, + { 0x3104, 0x02410B00 }, + { 0x3106, 0x04050200 }, + { 0x3108, 0x42410C03 }, + { 0x310A, 0xE2410227 }, + { 0x310C, 0x02413B01 }, + { 0x310E, 0xE2414266 }, + { 0x3110, 0xE2415294 }, + { 0x3112, 0x02410B00 }, + { 0x3114, 0x02410B00 }, + { 0x3116, 0x02281100 }, + { 0x3118, 0x02281401 }, + { 0x311A, 0x02280200 }, + { 0x311C, 0x02281001 }, + { 0x311E, 0x02280200 }, + { 0x3120, 0xE2410266 }, + { 0x3122, 0x82414B17 }, + { 0x3124, 0x82410B17 }, + { 0x3126, 0xE2415294 }, + { 0x3128, 0x02410B00 }, + { 0x312A, 0x8228160D }, + { 0x312C, 0x0228F501 }, + { 0x312E, 0x8228061C }, + { 0x3130, 0x02281000 }, + { 0x3132, 0x04051101 }, + { 0x3134, 0x02281800 }, + { 0x3136, 0x42281203 }, + { 0x3138, 0x02281101 }, + { 0x313A, 0xC2281300 }, + { 0x313C, 0x2228FB02 }, + { 0x3140, 0xC2293632 }, + { 0x3142, 0xC2500001 }, + { 0x3144, 0x8229100E }, + { 0x3146, 0x22291803 }, + { 0x3148, 0x82510B00 }, + { 0x314A, 0xE251023B }, + { 0x314C, 0x02513B01 }, + { 0x314E, 0x62500000 }, + { 0x3150, 0xE2514288 }, + { 0x3152, 0x02510B00 }, + { 0x3154, 0x02510B00 }, + { 0x3156, 0x04050500 }, + { 0x3158, 0x42510C02 }, + { 0x315A, 0xE2510227 }, + { 0x315C, 0x02513B01 }, + { 0x315E, 0xE2514266 }, + { 0x3160, 0xE2515294 }, + { 0x3162, 0x02510B00 }, + { 0x3164, 0x02510B00 }, + { 0x3166, 0x02291100 }, + { 0x3168, 0x02291401 }, + { 0x316A, 0x02290200 }, + { 0x316C, 0x02291001 }, + { 0x316E, 0x02290200 }, + { 0x3170, 0xE2510266 }, + { 0x3172, 0x82514B15 }, + { 0x3174, 0x82510B15 }, + { 0x3176, 0xE2515294 }, + { 0x3178, 0x02510B00 }, + { 0x317A, 0x8229160D }, + { 0x317C, 0x0229F501 }, + { 0x317E, 0x8229061C }, + { 0x3180, 0x02291000 }, + { 0x3182, 0x04051101 }, + { 0x3184, 0x02291800 }, + { 0x3186, 0x42291203 }, + { 0x3188, 0x02291101 }, + { 0x318A, 0xC2291300 }, + { 0x318C, 0x2229FB02 }, + { 0x3190, 0xC22A3632 }, + { 0x3192, 0xC2500001 }, + { 0x3194, 0x822A100E }, + { 0x3196, 0x222A1803 }, + { 0x3198, 0x82510B02 }, + { 0x319A, 0xE251023B }, + { 0x319C, 0x02513B01 }, + { 0x319E, 0x62500000 }, + { 0x31A0, 0xE2514288 }, + { 0x31A2, 0x02510B00 }, + { 0x31A4, 0x02510B00 }, + { 0x31A6, 0x04050400 }, + { 0x31A8, 0x42510C03 }, + { 0x31AA, 0xE2510227 }, + { 0x31AC, 0x02513B01 }, + { 0x31AE, 0xE2514266 }, + { 0x31B0, 0xE2515294 }, + { 0x31B2, 0x02510B00 }, + { 0x31B4, 0x02510B00 }, + { 0x31B6, 0x022A1100 }, + { 0x31B8, 0x022A1401 }, + { 0x31BA, 0x022A0200 }, + { 0x31BC, 0x022A1001 }, + { 0x31BE, 0x022A0200 }, + { 0x31C0, 0xE2510266 }, + { 0x31C2, 0x82514B17 }, + { 0x31C4, 0x82510B17 }, + { 0x31C6, 0xE2515294 }, + { 0x31C8, 0x02510B00 }, + { 0x31CA, 0x822A160D }, + { 0x31CC, 0x022AF501 }, + { 0x31CE, 0x822A061C }, + { 0x31D0, 0x022A1000 }, + { 0x31D2, 0x04051101 }, + { 0x31D4, 0x022A1800 }, + { 0x31D6, 0x422A1203 }, + { 0x31D8, 0x022A1101 }, + { 0x31DA, 0xC22A1300 }, + { 0x31DC, 0x222AFB02 }, +}; + +static const struct reg_sequence cs47l85_revc_32_patch[] = { + { 0x3380, 0xE4103066 }, + { 0x3382, 0xE4103070 }, + { 0x3384, 0xE4103078 }, + { 0x3386, 0xE4103080 }, + { 0x3388, 0xE410F080 }, + { 0x338A, 0xE4143066 }, + { 0x338C, 0xE4143070 }, + { 0x338E, 0xE4143078 }, + { 0x3390, 0xE4143080 }, + { 0x3392, 0xE414F080 }, + { 0x3394, 0xE4103078 }, + { 0x3396, 0xE4103070 }, + { 0x3398, 0xE4103066 }, + { 0x339A, 0xE410F056 }, + { 0x339C, 0xE4143078 }, + { 0x339E, 0xE4143070 }, + { 0x33A0, 0xE4143066 }, + { 0x33A2, 0xE414F056 }, +}; + +int cs47l85_patch(struct madera *madera) +{ + int ret = 0; + const struct reg_sequence *patch16; + const struct reg_sequence *patch32; + unsigned int num16, num32; + + switch (madera->rev) { + case 0: + case 1: + patch16 = cs47l85_reva_16_patch; + num16 = ARRAY_SIZE(cs47l85_reva_16_patch); + + patch32 = cs47l85_reva_32_patch; + num32 = ARRAY_SIZE(cs47l85_reva_32_patch); + break; + default: + patch16 = cs47l85_revc_16_patch; + num16 = ARRAY_SIZE(cs47l85_revc_16_patch); + + patch32 = cs47l85_revc_32_patch; + num32 = ARRAY_SIZE(cs47l85_revc_32_patch); + break; + } + + ret = regmap_register_patch(madera->regmap, patch16, num16); + if (ret < 0) { + dev_err(madera->dev, + "Error in applying 16-bit patch: %d\n", ret); + return ret; + } + + ret = regmap_register_patch(madera->regmap_32bit, patch32, num32); + if (ret < 0) { + dev_err(madera->dev, + "Error in applying 32-bit patch: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cs47l85_patch); + +static const struct reg_default cs47l85_reg_default[] = { + { 0x00000020, 0x0000 }, /* R32 (0x20) - Tone Generator 1 */ + { 0x00000021, 0x1000 }, /* R33 (0x21) - Tone Generator 2 */ + { 0x00000022, 0x0000 }, /* R34 (0x22) - Tone Generator 3 */ + { 0x00000023, 0x1000 }, /* R35 (0x23) - Tone Generator 4 */ + { 0x00000024, 0x0000 }, /* R36 (0x24) - Tone Generator 5 */ + { 0x00000030, 0x0000 }, /* R48 (0x30) - PWM Drive 1 */ + { 0x00000031, 0x0100 }, /* R49 (0x31) - PWM Drive 2 */ + { 0x00000032, 0x0100 }, /* R50 (0x32) - PWM Drive 3 */ + { 0x00000061, 0x01ff }, /* R97 (0x61) - Sample Rate Sequence Select 1 */ + { 0x00000062, 0x01ff }, /* R98 (0x62) - Sample Rate Sequence Select 2 */ + { 0x00000063, 0x01ff }, /* R99 (0x63) - Sample Rate Sequence Select 3 */ + { 0x00000064, 0x01ff }, /* R100 (0x64) - Sample Rate Sequence Select 4 */ + { 0x00000066, 0x01ff }, /* R102 (0x66) - Always On Triggers Sequence Select 1*/ + { 0x00000067, 0x01ff }, /* R103 (0x67) - Always On Triggers Sequence Select 2*/ + { 0x00000090, 0x0000 }, /* R144 (0x90) - Haptics Control 1 */ + { 0x00000091, 0x7fff }, /* R145 (0x91) - Haptics Control 2 */ + { 0x00000092, 0x0000 }, /* R146 (0x92) - Haptics phase 1 intensity */ + { 0x00000093, 0x0000 }, /* R147 (0x93) - Haptics phase 1 duration */ + { 0x00000094, 0x0000 }, /* R148 (0x94) - Haptics phase 2 intensity */ + { 0x00000095, 0x0000 }, /* R149 (0x95) - Haptics phase 2 duration */ + { 0x00000096, 0x0000 }, /* R150 (0x96) - Haptics phase 3 intensity */ + { 0x00000097, 0x0000 }, /* R151 (0x97) - Haptics phase 3 duration */ + { 0x000000a0, 0x0000 }, /* R160 (0xa0) - Comfort Noise Generator */ + { 0x00000100, 0x0002 }, /* R256 (0x100) - Clock 32k 1 */ + { 0x00000101, 0x0404 }, /* R257 (0x101) - System Clock 1 */ + { 0x00000102, 0x0011 }, /* R258 (0x102) - Sample rate 1 */ + { 0x00000103, 0x0011 }, /* R259 (0x103) - Sample rate 2 */ + { 0x00000104, 0x0011 }, /* R260 (0x104) - Sample rate 3 */ + { 0x00000112, 0x0305 }, /* R274 (0x112) - Async clock 1 */ + { 0x00000113, 0x0011 }, /* R275 (0x113) - Async sample rate 1 */ + { 0x00000114, 0x0011 }, /* R276 (0x114) - Async sample rate 2 */ + { 0x00000120, 0x0305 }, /* R288 (0x120) - DSP Clock 1 */ + { 0x00000122, 0x0000 }, /* R290 (0x122) - DSP Clock 2 */ + { 0x00000149, 0x0000 }, /* R329 (0x149) - Output system clock */ + { 0x0000014a, 0x0000 }, /* R330 (0x14a) - Output async clock */ + { 0x00000152, 0x0000 }, /* R338 (0x152) - Rate Estimator 1 */ + { 0x00000153, 0x0000 }, /* R339 (0x153) - Rate Estimator 2 */ + { 0x00000154, 0x0000 }, /* R340 (0x154) - Rate Estimator 3 */ + { 0x00000155, 0x0000 }, /* R341 (0x155) - Rate Estimator 4 */ + { 0x00000156, 0x0000 }, /* R342 (0x156) - Rate Estimator 5 */ + { 0x00000171, 0x0002 }, /* R369 (0x171) - FLL1 Control 1 */ + { 0x00000172, 0x0008 }, /* R370 (0x172) - FLL1 Control 2 */ + { 0x00000173, 0x0018 }, /* R371 (0x173) - FLL1 Control 3 */ + { 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */ + { 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */ + { 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */ + { 0x00000177, 0x0281 }, /* R375 (0x177) - FLL1 Loop Filter Test 1 */ + { 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */ + { 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 1 */ + { 0x00000182, 0x0000 }, /* R386 (0x182) - FLL1 Synchroniser 2 */ + { 0x00000183, 0x0000 }, /* R387 (0x183) - FLL1 Synchroniser 3 */ + { 0x00000184, 0x0000 }, /* R388 (0x184) - FLL1 Synchroniser 4 */ + { 0x00000185, 0x0000 }, /* R389 (0x185) - FLL1 Synchroniser 5 */ + { 0x00000186, 0x0000 }, /* R390 (0x186) - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R391 (0x187) - FLL1 Synchroniser 7 */ + { 0x00000189, 0x0000 }, /* R393 (0x189) - FLL1 Spread Spectrum */ + { 0x0000018a, 0x000c }, /* R394 (0x18a) - FLL1 GPIO Clock */ + { 0x00000191, 0x0002 }, /* R401 (0x191) - FLL2 Control 1 */ + { 0x00000192, 0x0008 }, /* R402 (0x192) - FLL2 Control 2 */ + { 0x00000193, 0x0018 }, /* R403 (0x193) - FLL2 Control 3 */ + { 0x00000194, 0x007d }, /* R404 (0x194) - FLL2 Control 4 */ + { 0x00000195, 0x0000 }, /* R405 (0x195) - FLL2 Control 5 */ + { 0x00000196, 0x0000 }, /* R406 (0x196) - FLL2 Control 6 */ + { 0x00000197, 0x0281 }, /* R407 (0x197) - FLL2 Loop Filter Test 1 */ + { 0x00000199, 0x0000 }, /* R409 (0x199) - FLL2 Control 7 */ + { 0x000001a1, 0x0000 }, /* R417 (0x1a1) - FLL2 Synchroniser 1 */ + { 0x000001a2, 0x0000 }, /* R418 (0x1a2) - FLL2 Synchroniser 2 */ + { 0x000001a3, 0x0000 }, /* R419 (0x1a3) - FLL2 Synchroniser 3 */ + { 0x000001a4, 0x0000 }, /* R420 (0x1a4) - FLL2 Synchroniser 4 */ + { 0x000001a5, 0x0000 }, /* R421 (0x1a5) - FLL2 Synchroniser 5 */ + { 0x000001a6, 0x0000 }, /* R422 (0x1a6) - FLL2 Synchroniser 6 */ + { 0x000001a7, 0x0001 }, /* R423 (0x1a7) - FLL2 Synchroniser 7 */ + { 0x000001a9, 0x0000 }, /* R425 (0x1a9) - FLL2 Spread Spectrum */ + { 0x000001aa, 0x000c }, /* R426 (0x1aa) - FLL2 GPIO Clock */ + { 0x000001b1, 0x0002 }, /* R433 (0x1b1) - FLL3 Control 1 */ + { 0x000001b2, 0x0008 }, /* R434 (0x1b2) - FLL3 Control 2 */ + { 0x000001b3, 0x0018 }, /* R435 (0x1b3) - FLL3 Control 3 */ + { 0x000001b4, 0x007d }, /* R436 (0x1b4) - FLL3 Control 4 */ + { 0x000001b5, 0x0000 }, /* R437 (0x1b5) - FLL3 Control 5 */ + { 0x000001b6, 0x0000 }, /* R438 (0x1b6) - FLL3 Control 6 */ + { 0x000001b7, 0x0281 }, /* R439 (0x1b7) - FLL3 Loop Filter Test 1 */ + { 0x000001b9, 0x0000 }, /* R441 (0x1b9) - FLL3 Control 7 */ + { 0x000001c1, 0x0000 }, /* R449 (0x1c1) - FLL3 Synchroniser 1 */ + { 0x000001c2, 0x0000 }, /* R450 (0x1c2) - FLL3 Synchroniser 2 */ + { 0x000001c3, 0x0000 }, /* R451 (0x1c3) - FLL3 Synchroniser 3 */ + { 0x000001c4, 0x0000 }, /* R452 (0x1c4) - FLL3 Synchroniser 4 */ + { 0x000001c5, 0x0000 }, /* R453 (0x1c5) - FLL3 Synchroniser 5 */ + { 0x000001c6, 0x0000 }, /* R454 (0x1c6) - FLL3 Synchroniser 6 */ + { 0x000001c7, 0x0001 }, /* R455 (0x1c7) - FLL3 Synchroniser 7 */ + { 0x000001c9, 0x0000 }, /* R457 (0x1c9) - FLL3 Spread Spectrum */ + { 0x000001ca, 0x000C }, /* R458 (0x1ca) - FLL3 GPIO Clock */ + { 0x00000200, 0x0006 }, /* R512 (0x200) - Mic Charge Pump 1 */ + { 0x0000020b, 0x0400 }, /* R523 (0x20B) - HP Charge Pump 8 */ + { 0x00000210, 0x0184 }, /* R528 (0x210) - LDO1 Control 1 */ + { 0x00000213, 0x03e4 }, /* R531 (0x213) - LDO2 Control 1 */ + { 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */ + { 0x00000219, 0x00e6 }, /* R537 (0x219) - Mic Bias Ctrl 2 */ + { 0x0000021a, 0x00e6 }, /* R538 (0x21a) - Mic Bias Ctrl 3 */ + { 0x0000021b, 0x00e6 }, /* R539 (0x21b) - Mic Bias Ctrl 4 */ + { 0x0000027e, 0x0000 }, /* R638 (0x27e) - EDRE HP stereo control */ + { 0x00000293, 0x0000 }, /* R659 (0x293) - Accessory Detect Mode 1 */ + { 0x0000029b, 0x0000 }, /* R667 (0x29b) - Headphone Detect 1 */ + { 0x000002a3, 0x1102 }, /* R675 (0x2a3) - Mic Detect Control 1 */ + { 0x000002a4, 0x009f }, /* R676 (0x2a4) - Mic Detect Control 2 */ + { 0x000002a6, 0x3737 }, /* R678 (0x2a6) - Mic Detect Level 1 */ + { 0x000002a7, 0x2c37 }, /* R679 (0x2a7) - Mic Detect Level 2 */ + { 0x000002a8, 0x1422 }, /* R680 (0x2a8) - Mic Detect Level 3 */ + { 0x000002a9, 0x030a }, /* R681 (0x2a9) - Mic Detect Level 4 */ + { 0x000002c6, 0x0010 }, /* R710 (0x2c6) - Mic Clamp control */ + { 0x000002c8, 0x0000 }, /* R712 (0x2c8) - GP switch 1 */ + { 0x000002d3, 0x0000 }, /* R723 (0x2d3) - Jack detect analogue */ + { 0x00000300, 0x0000 }, /* R768 (0x300) - Input Enables */ + { 0x00000308, 0x0000 }, /* R776 (0x308) - Input Rate */ + { 0x00000309, 0x0022 }, /* R777 (0x309) - Input Volume Ramp */ + { 0x0000030c, 0x0002 }, /* R780 (0x30c) - HPF Control */ + { 0x00000310, 0x0080 }, /* R784 (0x310) - IN1L Control */ + { 0x00000311, 0x0180 }, /* R785 (0x311) - ADC Digital Volume 1L */ + { 0x00000312, 0x0500 }, /* R786 (0x312) - DMIC1L Control */ + { 0x00000314, 0x0080 }, /* R788 (0x314) - IN1R Control */ + { 0x00000315, 0x0180 }, /* R789 (0x315) - ADC Digital Volume 1R */ + { 0x00000316, 0x0000 }, /* R790 (0x316) - DMIC1R Control */ + { 0x00000318, 0x0080 }, /* R792 (0x318) - IN2L Control */ + { 0x00000319, 0x0180 }, /* R793 (0x319) - ADC Digital Volume 2L */ + { 0x0000031a, 0x0500 }, /* R794 (0x31a) - DMIC2L Control */ + { 0x0000031c, 0x0080 }, /* R796 (0x31c) - IN2R Control */ + { 0x0000031d, 0x0180 }, /* R797 (0x31d) - ADC Digital Volume 2R */ + { 0x0000031e, 0x0000 }, /* R798 (0x31e) - DMIC2R Control */ + { 0x00000320, 0x0080 }, /* R800 (0x320) - IN3L Control */ + { 0x00000321, 0x0180 }, /* R801 (0x321) - ADC Digital Volume 3L */ + { 0x00000322, 0x0500 }, /* R802 (0x322) - DMIC3L Control */ + { 0x00000324, 0x0080 }, /* R804 (0x324) - IN3R Control */ + { 0x00000325, 0x0180 }, /* R805 (0x325) - ADC Digital Volume 3R */ + { 0x00000326, 0x0000 }, /* R806 (0x326) - DMIC3R Control */ + { 0x00000328, 0x0000 }, /* R808 (0x328) - IN4 Control */ + { 0x00000329, 0x0180 }, /* R809 (0x329) - ADC Digital Volume 4L */ + { 0x0000032a, 0x0500 }, /* R810 (0x32a) - DMIC4L Control */ + { 0x0000032c, 0x0000 }, /* R812 (0x32c) - IN4R Control */ + { 0x0000032d, 0x0180 }, /* R813 (0x32d) - ADC Digital Volume 4R */ + { 0x0000032e, 0x0000 }, /* R814 (0x32e) - DMIC4R Control */ + { 0x00000330, 0x0000 }, /* R816 (0x330) - IN5L Control */ + { 0x00000331, 0x0180 }, /* R817 (0x331) - ADC Digital Volume 5L */ + { 0x00000332, 0x0500 }, /* R818 (0x332) - DMIC5L Control */ + { 0x00000334, 0x0000 }, /* R820 (0x334) - IN5R Control */ + { 0x00000335, 0x0180 }, /* R821 (0x335) - ADC Digital Volume 5R */ + { 0x00000336, 0x0000 }, /* R822 (0x336) - DMIC5R Control */ + { 0x00000338, 0x0000 }, /* R824 (0x338) - IN6L Control */ + { 0x00000339, 0x0180 }, /* R825 (0x339) - ADC Digital Volume 6L */ + { 0x0000033a, 0x0500 }, /* R826 (0x33a) - DMIC6L Control */ + { 0x0000033c, 0x0000 }, /* R828 (0x33c) - IN6R Control */ + { 0x0000033d, 0x0180 }, /* R829 (0x33d) - ADC Digital Volume 6R */ + { 0x0000033e, 0x0000 }, /* R830 (0x33e) - DMIC6R Control */ + { 0x00000400, 0x0000 }, /* R1024 (0x400) - Output Enables 1 */ + { 0x00000408, 0x0000 }, /* R1032 (0x408) - Output Rate 1 */ + { 0x00000409, 0x0022 }, /* R1033 (0x409) - Output Volume Ramp */ + { 0x00000410, 0x0080 }, /* R1040 (0x410) - Output Path Config 1L */ + { 0x00000411, 0x0180 }, /* R1041 (0x411) - DAC Digital Volume 1L */ + { 0x00000413, 0x0001 }, /* R1043 (0x413) - Noise Gate Select 1L */ + { 0x00000414, 0x0080 }, /* R1044 (0x414) - Output Path Config 1R */ + { 0x00000415, 0x0180 }, /* R1045 (0x415) - DAC Digital Volume 1R */ + { 0x00000417, 0x0002 }, /* R1047 (0x417) - Noise Gate Select 1R */ + { 0x00000418, 0x0080 }, /* R1048 (0x418) - Output Path Config 2L */ + { 0x00000419, 0x0180 }, /* R1049 (0x419) - DAC Digital Volume 2L */ + { 0x0000041b, 0x0004 }, /* R1051 (0x41b) - Noise Gate Select 2L */ + { 0x0000041c, 0x0080 }, /* R1052 (0x41c) - Output Path Config 2R */ + { 0x0000041d, 0x0180 }, /* R1053 (0x41d) - DAC Digital Volume 2R */ + { 0x0000041f, 0x0008 }, /* R1055 (0x41f) - Noise Gate Select 2R */ + { 0x00000420, 0x0080 }, /* R1056 (0x420) - Output Path Config 3L */ + { 0x00000421, 0x0180 }, /* R1057 (0x421) - DAC Digital Volume 3L */ + { 0x00000423, 0x0010 }, /* R1059 (0x423) - Noise Gate Select 3L */ + { 0x00000424, 0x0080 }, /* R1060 (0x424) - Output Path Config 3R */ + { 0x00000425, 0x0180 }, /* R1061 (0x425) - DAC Digital Volume 3R */ + { 0x00000427, 0x0020 }, /* R1063 (0x427) - Noise Gate Select 3R */ + { 0x00000428, 0x0000 }, /* R1064 (0x428) - Output Path Config 4L */ + { 0x00000429, 0x0180 }, /* R1065 (0x429) - DAC Digital Volume 4L */ + { 0x0000042b, 0x0040 }, /* R1067 (0x42b) - Noise Gate Select 4L */ + { 0x0000042c, 0x0000 }, /* R1068 (0x42c) - Output Path Config 4R */ + { 0x0000042d, 0x0180 }, /* R1069 (0x42d) - DAC Digital Volume 4R */ + { 0x0000042f, 0x0080 }, /* R1071 (0x42f) - Noise Gate Select 4R */ + { 0x00000430, 0x0000 }, /* R1072 (0x430) - Output Path Config 5L */ + { 0x00000431, 0x0180 }, /* R1073 (0x431) - DAC Digital Volume 5L */ + { 0x00000433, 0x0100 }, /* R1075 (0x433) - Noise Gate Select 5L */ + { 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */ + { 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */ + { 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */ + { 0x00000438, 0x0000 }, /* R1080 (0x438) - Output Path Config 6L */ + { 0x00000439, 0x0180 }, /* R1081 (0x439) - DAC Digital Volume 6L */ + { 0x0000043b, 0x0400 }, /* R1083 (0x43b) - Noise Gate Select 6L */ + { 0x0000043c, 0x0000 }, /* R1084 (0x43c) - Output Path Config 6R */ + { 0x0000043d, 0x0180 }, /* R1085 (0x43d) - DAC Digital Volume 6R */ + { 0x0000043f, 0x0800 }, /* R1087 (0x43f) - Noise Gate Select 6R */ + { 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */ + { 0x00000448, 0x003f }, /* R1096 (0x448) - EDRE Enable */ + { 0x0000044a, 0x0000 }, /* R1098 (0x44a) - EDRE Manual */ + { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ + { 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */ + { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ + { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ + { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ + { 0x00000492, 0x0069 }, /* R1170 (0x492) - PDM SPK2 CTRL 1 */ + { 0x00000493, 0x0000 }, /* R1171 (0x493) - PDM SPK2 CTRL 2 */ + { 0x000004a0, 0x3210 }, /* R1184 (0x4a0) - HP1 Short Circuit Ctrl */ + { 0x000004a1, 0x3200 }, /* R1185 (0x4a1) - HP2 Short Circuit Ctrl */ + { 0x000004a2, 0x3200 }, /* R1186 (0x4a2) - HP3 Short Circuit Ctrl */ + { 0x000004a8, 0x7020 }, /* R1192 (0x4a8) - HP Test Ctrl 5 */ + { 0x000004a9, 0x7020 }, /* R1193 (0x4a9) - HP Test Ctrl 6 */ + { 0x00000500, 0x000c }, /* R1280 (0x500) - AIF1 BCLK Ctrl */ + { 0x00000501, 0x0000 }, /* R1281 (0x501) - AIF1 Tx Pin Ctrl */ + { 0x00000502, 0x0000 }, /* R1282 (0x502) - AIF1 Rx Pin Ctrl */ + { 0x00000503, 0x0000 }, /* R1283 (0x503) - AIF1 Rate Ctrl */ + { 0x00000504, 0x0000 }, /* R1284 (0x504) - AIF1 Format */ + { 0x00000506, 0x0040 }, /* R1286 (0x506) - AIF1 Rx BCLK Rate */ + { 0x00000507, 0x1818 }, /* R1287 (0x507) - AIF1 Frame Ctrl 1 */ + { 0x00000508, 0x1818 }, /* R1288 (0x508) - AIF1 Frame Ctrl 2 */ + { 0x00000509, 0x0000 }, /* R1289 (0x509) - AIF1 Frame Ctrl 3 */ + { 0x0000050a, 0x0001 }, /* R1290 (0x50a) - AIF1 Frame Ctrl 4 */ + { 0x0000050b, 0x0002 }, /* R1291 (0x50b) - AIF1 Frame Ctrl 5 */ + { 0x0000050c, 0x0003 }, /* R1292 (0x50c) - AIF1 Frame Ctrl 6 */ + { 0x0000050d, 0x0004 }, /* R1293 (0x50d) - AIF1 Frame Ctrl 7 */ + { 0x0000050e, 0x0005 }, /* R1294 (0x50e) - AIF1 Frame Ctrl 8 */ + { 0x0000050f, 0x0006 }, /* R1295 (0x50f) - AIF1 Frame Ctrl 9 */ + { 0x00000510, 0x0007 }, /* R1296 (0x510) - AIF1 Frame Ctrl 10 */ + { 0x00000511, 0x0000 }, /* R1297 (0x511) - AIF1 Frame Ctrl 11 */ + { 0x00000512, 0x0001 }, /* R1298 (0x512) - AIF1 Frame Ctrl 12 */ + { 0x00000513, 0x0002 }, /* R1299 (0x513) - AIF1 Frame Ctrl 13 */ + { 0x00000514, 0x0003 }, /* R1300 (0x514) - AIF1 Frame Ctrl 14 */ + { 0x00000515, 0x0004 }, /* R1301 (0x515) - AIF1 Frame Ctrl 15 */ + { 0x00000516, 0x0005 }, /* R1302 (0x516) - AIF1 Frame Ctrl 16 */ + { 0x00000517, 0x0006 }, /* R1303 (0x517) - AIF1 Frame Ctrl 17 */ + { 0x00000518, 0x0007 }, /* R1304 (0x518) - AIF1 Frame Ctrl 18 */ + { 0x00000519, 0x0000 }, /* R1305 (0x519) - AIF1 Tx Enables */ + { 0x0000051a, 0x0000 }, /* R1306 (0x51a) - AIF1 Rx Enables */ + { 0x00000540, 0x000c }, /* R1344 (0x540) - AIF2 BCLK Ctrl */ + { 0x00000541, 0x0000 }, /* R1345 (0x541) - AIF2 Tx Pin Ctrl */ + { 0x00000542, 0x0000 }, /* R1346 (0x542) - AIF2 Rx Pin Ctrl */ + { 0x00000543, 0x0000 }, /* R1347 (0x543) - AIF2 Rate Ctrl */ + { 0x00000544, 0x0000 }, /* R1348 (0x544) - AIF2 Format */ + { 0x00000546, 0x0040 }, /* R1350 (0x546) - AIF2 Rx BCLK Rate */ + { 0x00000547, 0x1818 }, /* R1351 (0x547) - AIF2 Frame Ctrl 1 */ + { 0x00000548, 0x1818 }, /* R1352 (0x548) - AIF2 Frame Ctrl 2 */ + { 0x00000549, 0x0000 }, /* R1353 (0x549) - AIF2 Frame Ctrl 3 */ + { 0x0000054a, 0x0001 }, /* R1354 (0x54a) - AIF2 Frame Ctrl 4 */ + { 0x0000054b, 0x0002 }, /* R1355 (0x54b) - AIF2 Frame Ctrl 5 */ + { 0x0000054c, 0x0003 }, /* R1356 (0x54c) - AIF2 Frame Ctrl 6 */ + { 0x0000054d, 0x0004 }, /* R1357 (0x54d) - AIF2 Frame Ctrl 7 */ + { 0x0000054e, 0x0005 }, /* R1358 (0x54e) - AIF2 Frame Ctrl 8 */ + { 0x0000054f, 0x0006 }, /* R1359 (0x54f) - AIF2 Frame Ctrl 9 */ + { 0x00000550, 0x0007 }, /* R1360 (0x550) - AIF2 Frame Ctrl 10 */ + { 0x00000551, 0x0000 }, /* R1361 (0x551) - AIF2 Frame Ctrl 11 */ + { 0x00000552, 0x0001 }, /* R1362 (0x552) - AIF2 Frame Ctrl 12 */ + { 0x00000553, 0x0002 }, /* R1363 (0x553) - AIF2 Frame Ctrl 13 */ + { 0x00000554, 0x0003 }, /* R1364 (0x554) - AIF2 Frame Ctrl 14 */ + { 0x00000555, 0x0004 }, /* R1365 (0x555) - AIF2 Frame Ctrl 15 */ + { 0x00000556, 0x0005 }, /* R1366 (0x556) - AIF2 Frame Ctrl 16 */ + { 0x00000557, 0x0006 }, /* R1367 (0x557) - AIF2 Frame Ctrl 17 */ + { 0x00000558, 0x0007 }, /* R1368 (0x558) - AIF2 Frame Ctrl 18 */ + { 0x00000559, 0x0000 }, /* R1369 (0x559) - AIF2 Tx Enables */ + { 0x0000055a, 0x0000 }, /* R1370 (0x55a) - AIF2 Rx Enables */ + { 0x00000580, 0x000c }, /* R1408 (0x580) - AIF3 BCLK Ctrl */ + { 0x00000581, 0x0000 }, /* R1409 (0x581) - AIF3 Tx Pin Ctrl */ + { 0x00000582, 0x0000 }, /* R1410 (0x582) - AIF3 Rx Pin Ctrl */ + { 0x00000583, 0x0000 }, /* R1411 (0x583) - AIF3 Rate Ctrl */ + { 0x00000584, 0x0000 }, /* R1412 (0x584) - AIF3 Format */ + { 0x00000586, 0x0040 }, /* R1414 (0x586) - AIF3 Rx BCLK Rate */ + { 0x00000587, 0x1818 }, /* R1415 (0x587) - AIF3 Frame Ctrl 1 */ + { 0x00000588, 0x1818 }, /* R1416 (0x588) - AIF3 Frame Ctrl 2 */ + { 0x00000589, 0x0000 }, /* R1417 (0x589) - AIF3 Frame Ctrl 3 */ + { 0x0000058a, 0x0001 }, /* R1418 (0x58a) - AIF3 Frame Ctrl 4 */ + { 0x00000591, 0x0000 }, /* R1425 (0x591) - AIF3 Frame Ctrl 11 */ + { 0x00000592, 0x0001 }, /* R1426 (0x592) - AIF3 Frame Ctrl 12 */ + { 0x00000599, 0x0000 }, /* R1433 (0x599) - AIF3 Tx Enables */ + { 0x0000059a, 0x0000 }, /* R1434 (0x59a) - AIF3 Rx Enables */ + { 0x000005a0, 0x000c }, /* R1440 (0x5a0) - AIF4 BCLK Ctrl */ + { 0x000005a1, 0x0000 }, /* R1441 (0x5a1) - AIF4 Tx Pin Ctrl */ + { 0x000005a2, 0x0000 }, /* R1442 (0x5a2) - AIF4 Rx Pin Ctrl */ + { 0x000005a3, 0x0000 }, /* R1443 (0x5a3) - AIF4 Rate Ctrl */ + { 0x000005a4, 0x0000 }, /* R1444 (0x5a4) - AIF4 Format */ + { 0x000005a6, 0x0040 }, /* R1446 (0x5a6) - AIF4 Rx BCLK Rate */ + { 0x000005a7, 0x1818 }, /* R1447 (0x5a7) - AIF4 Frame Ctrl 1 */ + { 0x000005a8, 0x1818 }, /* R1448 (0x5a8) - AIF4 Frame Ctrl 2 */ + { 0x000005a9, 0x0000 }, /* R1449 (0x5a9) - AIF4 Frame Ctrl 3 */ + { 0x000005aa, 0x0001 }, /* R1450 (0x5aa) - AIF4 Frame Ctrl 4 */ + { 0x000005b1, 0x0000 }, /* R1457 (0x5b1) - AIF4 Frame Ctrl 11 */ + { 0x000005b2, 0x0001 }, /* R1458 (0x5b2) - AIF4 Frame Ctrl 12 */ + { 0x000005b9, 0x0000 }, /* R1465 (0x5b9) - AIF4 Tx Enables */ + { 0x000005ba, 0x0000 }, /* R1466 (0x5ba) - AIF4 Rx Enables */ + { 0x000005c2, 0x0000 }, /* R1474 (0x5c2) - SPD1 TX Control */ + { 0x000005e3, 0x0000 }, /* R1507 (0x5e3) - SLIMbus Framer Ref Gear */ + { 0x000005e5, 0x0000 }, /* R1509 (0x5e5) - SLIMbus Rates 1 */ + { 0x000005e6, 0x0000 }, /* R1510 (0x5e6) - SLIMbus Rates 2 */ + { 0x000005e7, 0x0000 }, /* R1511 (0x5e7) - SLIMbus Rates 3 */ + { 0x000005e8, 0x0000 }, /* R1512 (0x5e8) - SLIMbus Rates 4 */ + { 0x000005e9, 0x0000 }, /* R1513 (0x5e9) - SLIMbus Rates 5 */ + { 0x000005ea, 0x0000 }, /* R1514 (0x5ea) - SLIMbus Rates 6 */ + { 0x000005eb, 0x0000 }, /* R1515 (0x5eb) - SLIMbus Rates 7 */ + { 0x000005ec, 0x0000 }, /* R1516 (0x5ec) - SLIMbus Rates 8 */ + { 0x000005f5, 0x0000 }, /* R1525 (0x5f5) - SLIMbus RX Channel Enable */ + { 0x000005f6, 0x0000 }, /* R1526 (0x5F6) - SLIMbus TX Channel Enable */ + { 0x00000640, 0x0000 }, /* R1600 (0x640) - PWM1MIX Input 1 Source */ + { 0x00000641, 0x0080 }, /* R1601 (0x641) - PWM1MIX Input 1 Volume */ + { 0x00000642, 0x0000 }, /* R1602 (0x642) - PWM1MIX Input 2 Source */ + { 0x00000643, 0x0080 }, /* R1603 (0x643) - PWM1MIX Input 2 Volume */ + { 0x00000644, 0x0000 }, /* R1604 (0x644) - PWM1MIX Input 3 Source */ + { 0x00000645, 0x0080 }, /* R1605 (0x645) - PWM1MIX Input 3 Volume */ + { 0x00000646, 0x0000 }, /* R1606 (0x646) - PWM1MIX Input 4 Source */ + { 0x00000647, 0x0080 }, /* R1607 (0x647) - PWM1MIX Input 4 Volume */ + { 0x00000648, 0x0000 }, /* R1608 (0x648) - PWM2MIX Input 1 Source */ + { 0x00000649, 0x0080 }, /* R1609 (0x649) - PWM2MIX Input 1 Volume */ + { 0x0000064a, 0x0000 }, /* R1610 (0x64a) - PWM2MIX Input 2 Source */ + { 0x0000064b, 0x0080 }, /* R1611 (0x64b) - PWM2MIX Input 2 Volume */ + { 0x0000064c, 0x0000 }, /* R1612 (0x64c) - PWM2MIX Input 3 Source */ + { 0x0000064d, 0x0080 }, /* R1613 (0x64d) - PWM2MIX Input 3 Volume */ + { 0x0000064e, 0x0000 }, /* R1614 (0x64e) - PWM2MIX Input 4 Source */ + { 0x0000064f, 0x0080 }, /* R1615 (0x64f) - PWM2MIX Input 4 Volume */ + { 0x00000680, 0x0000 }, /* R1664 (0x680) - OUT1LMIX Input 1 Source */ + { 0x00000681, 0x0080 }, /* R1665 (0x681) - OUT1LMIX Input 1 Volume */ + { 0x00000682, 0x0000 }, /* R1666 (0x682) - OUT1LMIX Input 2 Source */ + { 0x00000683, 0x0080 }, /* R1667 (0x683) - OUT1LMIX Input 2 Volume */ + { 0x00000684, 0x0000 }, /* R1668 (0x684) - OUT1LMIX Input 3 Source */ + { 0x00000685, 0x0080 }, /* R1669 (0x685) - OUT1LMIX Input 3 Volume */ + { 0x00000686, 0x0000 }, /* R1670 (0x686) - OUT1LMIX Input 4 Source */ + { 0x00000687, 0x0080 }, /* R1671 (0x687) - OUT1LMIX Input 4 Volume */ + { 0x00000688, 0x0000 }, /* R1672 (0x688) - OUT1RMIX Input 1 Source */ + { 0x00000689, 0x0080 }, /* R1673 (0x689) - OUT1RMIX Input 1 Volume */ + { 0x0000068a, 0x0000 }, /* R1674 (0x68a) - OUT1RMIX Input 2 Source */ + { 0x0000068b, 0x0080 }, /* R1675 (0x68b) - OUT1RMIX Input 2 Volume */ + { 0x0000068c, 0x0000 }, /* R1672 (0x68c) - OUT1RMIX Input 3 Source */ + { 0x0000068d, 0x0080 }, /* R1673 (0x68d) - OUT1RMIX Input 3 Volume */ + { 0x0000068e, 0x0000 }, /* R1674 (0x68e) - OUT1RMIX Input 4 Source */ + { 0x0000068f, 0x0080 }, /* R1675 (0x68f) - OUT1RMIX Input 4 Volume */ + { 0x00000690, 0x0000 }, /* R1680 (0x690) - OUT2LMIX Input 1 Source */ + { 0x00000691, 0x0080 }, /* R1681 (0x691) - OUT2LMIX Input 1 Volume */ + { 0x00000692, 0x0000 }, /* R1682 (0x692) - OUT2LMIX Input 2 Source */ + { 0x00000693, 0x0080 }, /* R1683 (0x693) - OUT2LMIX Input 2 Volume */ + { 0x00000694, 0x0000 }, /* R1684 (0x694) - OUT2LMIX Input 3 Source */ + { 0x00000695, 0x0080 }, /* R1685 (0x695) - OUT2LMIX Input 3 Volume */ + { 0x00000696, 0x0000 }, /* R1686 (0x696) - OUT2LMIX Input 4 Source */ + { 0x00000697, 0x0080 }, /* R1687 (0x697) - OUT2LMIX Input 4 Volume */ + { 0x00000698, 0x0000 }, /* R1688 (0x698) - OUT2RMIX Input 1 Source */ + { 0x00000699, 0x0080 }, /* R1689 (0x699) - OUT2RMIX Input 1 Volume */ + { 0x0000069a, 0x0000 }, /* R1690 (0x69a) - OUT2RMIX Input 2 Source */ + { 0x0000069b, 0x0080 }, /* R1691 (0x69b) - OUT2RMIX Input 2 Volume */ + { 0x0000069c, 0x0000 }, /* R1692 (0x69c) - OUT2RMIX Input 3 Source */ + { 0x0000069d, 0x0080 }, /* R1693 (0x69d) - OUT2RMIX Input 3 Volume */ + { 0x0000069e, 0x0000 }, /* R1694 (0x69e) - OUT2RMIX Input 4 Source */ + { 0x0000069f, 0x0080 }, /* R1695 (0x69f) - OUT2RMIX Input 4 Volume */ + { 0x000006a0, 0x0000 }, /* R1696 (0x6a0) - OUT3LMIX Input 1 Source */ + { 0x000006a1, 0x0080 }, /* R1697 (0x6a1) - OUT3LMIX Input 1 Volume */ + { 0x000006a2, 0x0000 }, /* R1698 (0x6a2) - OUT3LMIX Input 2 Source */ + { 0x000006a3, 0x0080 }, /* R1699 (0x6a3) - OUT3LMIX Input 2 Volume */ + { 0x000006a4, 0x0000 }, /* R1700 (0x6a4) - OUT3LMIX Input 3 Source */ + { 0x000006a5, 0x0080 }, /* R1701 (0x6a5) - OUT3LMIX Input 3 Volume */ + { 0x000006a6, 0x0000 }, /* R1702 (0x6a6) - OUT3LMIX Input 4 Source */ + { 0x000006a7, 0x0080 }, /* R1703 (0x6a7) - OUT3LMIX Input 4 Volume */ + { 0x000006a8, 0x0000 }, /* R1704 (0x6a8) - OUT3RMIX Input 1 Source */ + { 0x000006a9, 0x0080 }, /* R1705 (0x6a9) - OUT3RMIX Input 1 Volume */ + { 0x000006aa, 0x0000 }, /* R1706 (0x6aa) - OUT3RMIX Input 2 Source */ + { 0x000006ab, 0x0080 }, /* R1707 (0x6ab) - OUT3RMIX Input 2 Volume */ + { 0x000006ac, 0x0000 }, /* R1708 (0x6ac) - OUT3RMIX Input 3 Source */ + { 0x000006ad, 0x0080 }, /* R1709 (0x6ad) - OUT3RMIX Input 3 Volume */ + { 0x000006ae, 0x0000 }, /* R1710 (0x6ae) - OUT3RMIX Input 4 Source */ + { 0x000006af, 0x0080 }, /* R1711 (0x6af) - OUT3RMIX Input 4 Volume */ + { 0x000006b0, 0x0000 }, /* R1712 (0x6b0) - OUT4LMIX Input 1 Source */ + { 0x000006b1, 0x0080 }, /* R1713 (0x6b1) - OUT4LMIX Input 1 Volume */ + { 0x000006b2, 0x0000 }, /* R1714 (0x6b2) - OUT4LMIX Input 2 Source */ + { 0x000006b3, 0x0080 }, /* R1715 (0x6b3) - OUT4LMIX Input 2 Volume */ + { 0x000006b4, 0x0000 }, /* R1716 (0x6b4) - OUT4LMIX Input 3 Source */ + { 0x000006b5, 0x0080 }, /* R1717 (0x6b5) - OUT4LMIX Input 3 Volume */ + { 0x000006b6, 0x0000 }, /* R1718 (0x6b6) - OUT4LMIX Input 4 Source */ + { 0x000006b7, 0x0080 }, /* R1719 (0x6b7) - OUT4LMIX Input 4 Volume */ + { 0x000006b8, 0x0000 }, /* R1720 (0x6b8) - OUT4RMIX Input 1 Source */ + { 0x000006b9, 0x0080 }, /* R1721 (0x6b9) - OUT4RMIX Input 1 Volume */ + { 0x000006ba, 0x0000 }, /* R1722 (0x6ba) - OUT4RMIX Input 2 Source */ + { 0x000006bb, 0x0080 }, /* R1723 (0x6bb) - OUT4RMIX Input 2 Volume */ + { 0x000006bc, 0x0000 }, /* R1724 (0x6bc) - OUT4RMIX Input 3 Source */ + { 0x000006bd, 0x0080 }, /* R1725 (0x6bd) - OUT4RMIX Input 3 Volume */ + { 0x000006be, 0x0000 }, /* R1726 (0x6be) - OUT4RMIX Input 4 Source */ + { 0x000006bf, 0x0080 }, /* R1727 (0x6bf) - OUT4RMIX Input 4 Volume */ + { 0x000006c0, 0x0000 }, /* R1728 (0x6c0) - OUT5LMIX Input 1 Source */ + { 0x000006c1, 0x0080 }, /* R1729 (0x6c1) - OUT5LMIX Input 1 Volume */ + { 0x000006c2, 0x0000 }, /* R1730 (0x6c2) - OUT5LMIX Input 2 Source */ + { 0x000006c3, 0x0080 }, /* R1731 (0x6c3) - OUT5LMIX Input 2 Volume */ + { 0x000006c4, 0x0000 }, /* R1732 (0x6c4) - OUT5LMIX Input 3 Source */ + { 0x000006c5, 0x0080 }, /* R1733 (0x6c5) - OUT5LMIX Input 3 Volume */ + { 0x000006c6, 0x0000 }, /* R1734 (0x6c6) - OUT5LMIX Input 4 Source */ + { 0x000006c7, 0x0080 }, /* R1735 (0x6c7) - OUT5LMIX Input 4 Volume */ + { 0x000006c8, 0x0000 }, /* R1736 (0x6c8) - OUT5RMIX Input 1 Source */ + { 0x000006c9, 0x0080 }, /* R1737 (0x6c9) - OUT5RMIX Input 1 Volume */ + { 0x000006ca, 0x0000 }, /* R1738 (0x6ca) - OUT5RMIX Input 2 Source */ + { 0x000006cb, 0x0080 }, /* R1739 (0x6cb) - OUT5RMIX Input 2 Volume */ + { 0x000006cc, 0x0000 }, /* R1740 (0x6cc) - OUT5RMIX Input 3 Source */ + { 0x000006cd, 0x0080 }, /* R1741 (0x6cd) - OUT5RMIX Input 3 Volume */ + { 0x000006ce, 0x0000 }, /* R1742 (0x6ce) - OUT5RMIX Input 4 Source */ + { 0x000006cf, 0x0080 }, /* R1743 (0x6cf) - OUT5RMIX Input 4 Volume */ + { 0x000006d0, 0x0000 }, /* R1744 (0x6d0) - OUT6LMIX Input 1 Source */ + { 0x000006d1, 0x0080 }, /* R1745 (0x6d1) - OUT6LMIX Input 1 Volume */ + { 0x000006d2, 0x0000 }, /* R1746 (0x6d2) - OUT6LMIX Input 2 Source */ + { 0x000006d3, 0x0080 }, /* R1747 (0x6d3) - OUT6LMIX Input 2 Volume */ + { 0x000006d4, 0x0000 }, /* R1748 (0x6d4) - OUT6LMIX Input 3 Source */ + { 0x000006d5, 0x0080 }, /* R1749 (0x6d5) - OUT6LMIX Input 3 Volume */ + { 0x000006d6, 0x0000 }, /* R1750 (0x6d6) - OUT6LMIX Input 4 Source */ + { 0x000006d7, 0x0080 }, /* R1751 (0x6d7) - OUT6LMIX Input 4 Volume */ + { 0x000006d8, 0x0000 }, /* R1752 (0x6d8) - OUT6RMIX Input 1 Source */ + { 0x000006d9, 0x0080 }, /* R1753 (0x6d9) - OUT6RMIX Input 1 Volume */ + { 0x000006da, 0x0000 }, /* R1754 (0x6da) - OUT6RMIX Input 2 Source */ + { 0x000006db, 0x0080 }, /* R1755 (0x6db) - OUT6RMIX Input 2 Volume */ + { 0x000006dc, 0x0000 }, /* R1756 (0x6dc) - OUT6RMIX Input 3 Source */ + { 0x000006dd, 0x0080 }, /* R1757 (0x6dd) - OUT6RMIX Input 3 Volume */ + { 0x000006de, 0x0000 }, /* R1758 (0x6de) - OUT6RMIX Input 4 Source */ + { 0x000006df, 0x0080 }, /* R1759 (0x6df) - OUT6RMIX Input 4 Volume */ + { 0x00000700, 0x0000 }, /* R1792 (0x700) - AIF1TX1MIX Input 1 Source */ + { 0x00000701, 0x0080 }, /* R1793 (0x701) - AIF1TX1MIX Input 1 Volume */ + { 0x00000702, 0x0000 }, /* R1794 (0x702) - AIF1TX1MIX Input 2 Source */ + { 0x00000703, 0x0080 }, /* R1795 (0x703) - AIF1TX1MIX Input 2 Volume */ + { 0x00000704, 0x0000 }, /* R1796 (0x704) - AIF1TX1MIX Input 3 Source */ + { 0x00000705, 0x0080 }, /* R1797 (0x705) - AIF1TX1MIX Input 3 Volume */ + { 0x00000706, 0x0000 }, /* R1798 (0x706) - AIF1TX1MIX Input 4 Source */ + { 0x00000707, 0x0080 }, /* R1799 (0x707) - AIF1TX1MIX Input 4 Volume */ + { 0x00000708, 0x0000 }, /* R1800 (0x708) - AIF1TX2MIX Input 1 Source */ + { 0x00000709, 0x0080 }, /* R1801 (0x709) - AIF1TX2MIX Input 1 Volume */ + { 0x0000070a, 0x0000 }, /* R1802 (0x70a) - AIF1TX2MIX Input 2 Source */ + { 0x0000070b, 0x0080 }, /* R1803 (0x70b) - AIF1TX2MIX Input 2 Volume */ + { 0x0000070c, 0x0000 }, /* R1804 (0x70c) - AIF1TX2MIX Input 3 Source */ + { 0x0000070d, 0x0080 }, /* R1805 (0x70d) - AIF1TX2MIX Input 3 Volume */ + { 0x0000070e, 0x0000 }, /* R1806 (0x70e) - AIF1TX2MIX Input 4 Source */ + { 0x0000070f, 0x0080 }, /* R1807 (0x70f) - AIF1TX2MIX Input 4 Volume */ + { 0x00000710, 0x0000 }, /* R1808 (0x710) - AIF1TX3MIX Input 1 Source */ + { 0x00000711, 0x0080 }, /* R1809 (0x711) - AIF1TX3MIX Input 1 Volume */ + { 0x00000712, 0x0000 }, /* R1810 (0x712) - AIF1TX3MIX Input 2 Source */ + { 0x00000713, 0x0080 }, /* R1811 (0x713) - AIF1TX3MIX Input 2 Volume */ + { 0x00000714, 0x0000 }, /* R1812 (0x714) - AIF1TX3MIX Input 3 Source */ + { 0x00000715, 0x0080 }, /* R1813 (0x715) - AIF1TX3MIX Input 3 Volume */ + { 0x00000716, 0x0000 }, /* R1814 (0x716) - AIF1TX3MIX Input 4 Source */ + { 0x00000717, 0x0080 }, /* R1815 (0x717) - AIF1TX3MIX Input 4 Volume */ + { 0x00000718, 0x0000 }, /* R1816 (0x718) - AIF1TX4MIX Input 1 Source */ + { 0x00000719, 0x0080 }, /* R1817 (0x719) - AIF1TX4MIX Input 1 Volume */ + { 0x0000071a, 0x0000 }, /* R1818 (0x71a) - AIF1TX4MIX Input 2 Source */ + { 0x0000071b, 0x0080 }, /* R1819 (0x71b) - AIF1TX4MIX Input 2 Volume */ + { 0x0000071c, 0x0000 }, /* R1820 (0x71c) - AIF1TX4MIX Input 3 Source */ + { 0x0000071d, 0x0080 }, /* R1821 (0x71d) - AIF1TX4MIX Input 3 Volume */ + { 0x0000071e, 0x0000 }, /* R1822 (0x71e) - AIF1TX4MIX Input 4 Source */ + { 0x0000071f, 0x0080 }, /* R1823 (0x71f) - AIF1TX4MIX Input 4 Volume */ + { 0x00000720, 0x0000 }, /* R1824 (0x720) - AIF1TX5MIX Input 1 Source */ + { 0x00000721, 0x0080 }, /* R1825 (0x721) - AIF1TX5MIX Input 1 Volume */ + { 0x00000722, 0x0000 }, /* R1826 (0x722) - AIF1TX5MIX Input 2 Source */ + { 0x00000723, 0x0080 }, /* R1827 (0x723) - AIF1TX5MIX Input 2 Volume */ + { 0x00000724, 0x0000 }, /* R1828 (0x724) - AIF1TX5MIX Input 3 Source */ + { 0x00000725, 0x0080 }, /* R1829 (0x725) - AIF1TX5MIX Input 3 Volume */ + { 0x00000726, 0x0000 }, /* R1830 (0x726) - AIF1TX5MIX Input 4 Source */ + { 0x00000727, 0x0080 }, /* R1831 (0x727) - AIF1TX5MIX Input 4 Volume */ + { 0x00000728, 0x0000 }, /* R1832 (0x728) - AIF1TX6MIX Input 1 Source */ + { 0x00000729, 0x0080 }, /* R1833 (0x729) - AIF1TX6MIX Input 1 Volume */ + { 0x0000072a, 0x0000 }, /* R1834 (0x72a) - AIF1TX6MIX Input 2 Source */ + { 0x0000072b, 0x0080 }, /* R1835 (0x72b) - AIF1TX6MIX Input 2 Volume */ + { 0x0000072c, 0x0000 }, /* R1836 (0x72c) - AIF1TX6MIX Input 3 Source */ + { 0x0000072d, 0x0080 }, /* R1837 (0x72d) - AIF1TX6MIX Input 3 Volume */ + { 0x0000072e, 0x0000 }, /* R1838 (0x72e) - AIF1TX6MIX Input 4 Source */ + { 0x0000072f, 0x0080 }, /* R1839 (0x72f) - AIF1TX6MIX Input 4 Volume */ + { 0x00000730, 0x0000 }, /* R1840 (0x730) - AIF1TX7MIX Input 1 Source */ + { 0x00000731, 0x0080 }, /* R1841 (0x731) - AIF1TX7MIX Input 1 Volume */ + { 0x00000732, 0x0000 }, /* R1842 (0x732) - AIF1TX7MIX Input 2 Source */ + { 0x00000733, 0x0080 }, /* R1843 (0x733) - AIF1TX7MIX Input 2 Volume */ + { 0x00000734, 0x0000 }, /* R1844 (0x734) - AIF1TX7MIX Input 3 Source */ + { 0x00000735, 0x0080 }, /* R1845 (0x735) - AIF1TX7MIX Input 3 Volume */ + { 0x00000736, 0x0000 }, /* R1846 (0x736) - AIF1TX7MIX Input 4 Source */ + { 0x00000737, 0x0080 }, /* R1847 (0x737) - AIF1TX7MIX Input 4 Volume */ + { 0x00000738, 0x0000 }, /* R1848 (0x738) - AIF1TX8MIX Input 1 Source */ + { 0x00000739, 0x0080 }, /* R1849 (0x739) - AIF1TX8MIX Input 1 Volume */ + { 0x0000073a, 0x0000 }, /* R1850 (0x73a) - AIF1TX8MIX Input 2 Source */ + { 0x0000073b, 0x0080 }, /* R1851 (0x73b) - AIF1TX8MIX Input 2 Volume */ + { 0x0000073c, 0x0000 }, /* R1852 (0x73c) - AIF1TX8MIX Input 3 Source */ + { 0x0000073d, 0x0080 }, /* R1853 (0x73d) - AIF1TX8MIX Input 3 Volume */ + { 0x0000073e, 0x0000 }, /* R1854 (0x73e) - AIF1TX8MIX Input 4 Source */ + { 0x0000073f, 0x0080 }, /* R1855 (0x73f) - AIF1TX8MIX Input 4 Volume */ + { 0x00000740, 0x0000 }, /* R1856 (0x740) - AIF2TX1MIX Input 1 Source */ + { 0x00000741, 0x0080 }, /* R1857 (0x741) - AIF2TX1MIX Input 1 Volume */ + { 0x00000742, 0x0000 }, /* R1858 (0x742) - AIF2TX1MIX Input 2 Source */ + { 0x00000743, 0x0080 }, /* R1859 (0x743) - AIF2TX1MIX Input 2 Volume */ + { 0x00000744, 0x0000 }, /* R1860 (0x744) - AIF2TX1MIX Input 3 Source */ + { 0x00000745, 0x0080 }, /* R1861 (0x745) - AIF2TX1MIX Input 3 Volume */ + { 0x00000746, 0x0000 }, /* R1862 (0x746) - AIF2TX1MIX Input 4 Source */ + { 0x00000747, 0x0080 }, /* R1863 (0x747) - AIF2TX1MIX Input 4 Volume */ + { 0x00000748, 0x0000 }, /* R1864 (0x748) - AIF2TX2MIX Input 1 Source */ + { 0x00000749, 0x0080 }, /* R1865 (0x749) - AIF2TX2MIX Input 1 Volume */ + { 0x0000074a, 0x0000 }, /* R1866 (0x74a) - AIF2TX2MIX Input 2 Source */ + { 0x0000074b, 0x0080 }, /* R1867 (0x74b) - AIF2TX2MIX Input 2 Volume */ + { 0x0000074c, 0x0000 }, /* R1868 (0x74c) - AIF2TX2MIX Input 3 Source */ + { 0x0000074d, 0x0080 }, /* R1869 (0x74d) - AIF2TX2MIX Input 3 Volume */ + { 0x0000074e, 0x0000 }, /* R1870 (0x74e) - AIF2TX2MIX Input 4 Source */ + { 0x0000074f, 0x0080 }, /* R1871 (0x74f) - AIF2TX2MIX Input 4 Volume */ + { 0x00000750, 0x0000 }, /* R1872 (0x750) - AIF2TX3MIX Input 1 Source */ + { 0x00000751, 0x0080 }, /* R1873 (0x751) - AIF2TX3MIX Input 1 Volume */ + { 0x00000752, 0x0000 }, /* R1874 (0x752) - AIF2TX3MIX Input 2 Source */ + { 0x00000753, 0x0080 }, /* R1875 (0x753) - AIF2TX3MIX Input 2 Volume */ + { 0x00000754, 0x0000 }, /* R1876 (0x754) - AIF2TX3MIX Input 3 Source */ + { 0x00000755, 0x0080 }, /* R1877 (0x755) - AIF2TX3MIX Input 3 Volume */ + { 0x00000756, 0x0000 }, /* R1878 (0x756) - AIF2TX3MIX Input 4 Source */ + { 0x00000757, 0x0080 }, /* R1879 (0x757) - AIF2TX3MIX Input 4 Volume */ + { 0x00000758, 0x0000 }, /* R1880 (0x758) - AIF2TX4MIX Input 1 Source */ + { 0x00000759, 0x0080 }, /* R1881 (0x759) - AIF2TX4MIX Input 1 Volume */ + { 0x0000075a, 0x0000 }, /* R1882 (0x75a) - AIF2TX4MIX Input 2 Source */ + { 0x0000075b, 0x0080 }, /* R1883 (0x75b) - AIF2TX4MIX Input 2 Volume */ + { 0x0000075c, 0x0000 }, /* R1884 (0x75c) - AIF2TX4MIX Input 3 Source */ + { 0x0000075d, 0x0080 }, /* R1885 (0x75d) - AIF2TX4MIX Input 3 Volume */ + { 0x0000075e, 0x0000 }, /* R1886 (0x75e) - AIF2TX4MIX Input 4 Source */ + { 0x0000075f, 0x0080 }, /* R1887 (0x75f) - AIF2TX4MIX Input 4 Volume */ + { 0x00000760, 0x0000 }, /* R1888 (0x760) - AIF2TX5MIX Input 1 Source */ + { 0x00000761, 0x0080 }, /* R1889 (0x761) - AIF2TX5MIX Input 1 Volume */ + { 0x00000762, 0x0000 }, /* R1890 (0x762) - AIF2TX5MIX Input 2 Source */ + { 0x00000763, 0x0080 }, /* R1891 (0x763) - AIF2TX5MIX Input 2 Volume */ + { 0x00000764, 0x0000 }, /* R1892 (0x764) - AIF2TX5MIX Input 3 Source */ + { 0x00000765, 0x0080 }, /* R1893 (0x765) - AIF2TX5MIX Input 3 Volume */ + { 0x00000766, 0x0000 }, /* R1894 (0x766) - AIF2TX5MIX Input 4 Source */ + { 0x00000767, 0x0080 }, /* R1895 (0x767) - AIF2TX5MIX Input 4 Volume */ + { 0x00000768, 0x0000 }, /* R1896 (0x768) - AIF2TX6MIX Input 1 Source */ + { 0x00000769, 0x0080 }, /* R1897 (0x769) - AIF2TX6MIX Input 1 Volume */ + { 0x0000076a, 0x0000 }, /* R1898 (0x76a) - AIF2TX6MIX Input 2 Source */ + { 0x0000076b, 0x0080 }, /* R1899 (0x76b) - AIF2TX6MIX Input 2 Volume */ + { 0x0000076c, 0x0000 }, /* R1900 (0x76c) - AIF2TX6MIX Input 3 Source */ + { 0x0000076d, 0x0080 }, /* R1901 (0x76d) - AIF2TX6MIX Input 3 Volume */ + { 0x0000076e, 0x0000 }, /* R1902 (0x76e) - AIF2TX6MIX Input 4 Source */ + { 0x0000076f, 0x0080 }, /* R1903 (0x76f) - AIF2TX6MIX Input 4 Volume */ + { 0x00000770, 0x0000 }, /* R1904 (0x770) - AIF2TX7MIX Input 1 Source */ + { 0x00000771, 0x0080 }, /* R1905 (0x771) - AIF2TX7MIX Input 1 Volume */ + { 0x00000772, 0x0000 }, /* R1906 (0x772) - AIF2TX7MIX Input 2 Source */ + { 0x00000773, 0x0080 }, /* R1907 (0x773) - AIF2TX7MIX Input 2 Volume */ + { 0x00000774, 0x0000 }, /* R1908 (0x774) - AIF2TX7MIX Input 3 Source */ + { 0x00000775, 0x0080 }, /* R1909 (0x775) - AIF2TX7MIX Input 3 Volume */ + { 0x00000776, 0x0000 }, /* R1910 (0x776) - AIF2TX7MIX Input 4 Source */ + { 0x00000777, 0x0080 }, /* R1911 (0x777) - AIF2TX7MIX Input 4 Volume */ + { 0x00000778, 0x0000 }, /* R1912 (0x778) - AIF2TX8MIX Input 1 Source */ + { 0x00000779, 0x0080 }, /* R1913 (0x779) - AIF2TX8MIX Input 1 Volume */ + { 0x0000077a, 0x0000 }, /* R1914 (0x77a) - AIF2TX8MIX Input 2 Source */ + { 0x0000077b, 0x0080 }, /* R1915 (0x77b) - AIF2TX8MIX Input 2 Volume */ + { 0x0000077c, 0x0000 }, /* R1916 (0x77c) - AIF2TX8MIX Input 3 Source */ + { 0x0000077d, 0x0080 }, /* R1917 (0x77d) - AIF2TX8MIX Input 3 Volume */ + { 0x0000077e, 0x0000 }, /* R1918 (0x77e) - AIF2TX8MIX Input 4 Source */ + { 0x0000077f, 0x0080 }, /* R1919 (0x77f) - AIF2TX8MIX Input 4 Volume */ + { 0x00000780, 0x0000 }, /* R1920 (0x780) - AIF3TX1MIX Input 1 Source */ + { 0x00000781, 0x0080 }, /* R1921 (0x781) - AIF3TX1MIX Input 1 Volume */ + { 0x00000782, 0x0000 }, /* R1922 (0x782) - AIF3TX1MIX Input 2 Source */ + { 0x00000783, 0x0080 }, /* R1923 (0x783) - AIF3TX1MIX Input 2 Volume */ + { 0x00000784, 0x0000 }, /* R1924 (0x784) - AIF3TX1MIX Input 3 Source */ + { 0x00000785, 0x0080 }, /* R1925 (0x785) - AIF3TX1MIX Input 3 Volume */ + { 0x00000786, 0x0000 }, /* R1926 (0x786) - AIF3TX1MIX Input 4 Source */ + { 0x00000787, 0x0080 }, /* R1927 (0x787) - AIF3TX1MIX Input 4 Volume */ + { 0x00000788, 0x0000 }, /* R1928 (0x788) - AIF3TX2MIX Input 1 Source */ + { 0x00000789, 0x0080 }, /* R1929 (0x789) - AIF3TX2MIX Input 1 Volume */ + { 0x0000078a, 0x0000 }, /* R1930 (0x78a) - AIF3TX2MIX Input 2 Source */ + { 0x0000078b, 0x0080 }, /* R1931 (0x78b) - AIF3TX2MIX Input 2 Volume */ + { 0x0000078c, 0x0000 }, /* R1932 (0x78c) - AIF3TX2MIX Input 3 Source */ + { 0x0000078d, 0x0080 }, /* R1933 (0x78d) - AIF3TX2MIX Input 3 Volume */ + { 0x0000078e, 0x0000 }, /* R1934 (0x78e) - AIF3TX2MIX Input 4 Source */ + { 0x0000078f, 0x0080 }, /* R1935 (0x78f) - AIF3TX2MIX Input 4 Volume */ + { 0x000007a0, 0x0000 }, /* R1952 (0x7a0) - AIF4TX1MIX Input 1 Source */ + { 0x000007a1, 0x0080 }, /* R1953 (0x7a1) - AIF4TX1MIX Input 1 Volume */ + { 0x000007a2, 0x0000 }, /* R1954 (0x7a2) - AIF4TX1MIX Input 2 Source */ + { 0x000007a3, 0x0080 }, /* R1955 (0x7a3) - AIF4TX1MIX Input 2 Volume */ + { 0x000007a4, 0x0000 }, /* R1956 (0x7a4) - AIF4TX1MIX Input 3 Source */ + { 0x000007a5, 0x0080 }, /* R1957 (0x7a5) - AIF4TX1MIX Input 3 Volume */ + { 0x000007a6, 0x0000 }, /* R1958 (0x7a6) - AIF4TX1MIX Input 4 Source */ + { 0x000007a7, 0x0080 }, /* R1959 (0x7a7) - AIF4TX1MIX Input 4 Volume */ + { 0x000007a8, 0x0000 }, /* R1960 (0x7a8) - AIF4TX2MIX Input 1 Source */ + { 0x000007a9, 0x0080 }, /* R1961 (0x7a9) - AIF4TX2MIX Input 1 Volume */ + { 0x000007aa, 0x0000 }, /* R1962 (0x7aa) - AIF4TX2MIX Input 2 Source */ + { 0x000007ab, 0x0080 }, /* R1963 (0x7ab) - AIF4TX2MIX Input 2 Volume */ + { 0x000007ac, 0x0000 }, /* R1964 (0x7ac) - AIF4TX2MIX Input 3 Source */ + { 0x000007ad, 0x0080 }, /* R1965 (0x7ad) - AIF4TX2MIX Input 3 Volume */ + { 0x000007ae, 0x0000 }, /* R1966 (0x7ae) - AIF4TX2MIX Input 4 Source */ + { 0x000007af, 0x0080 }, /* R1967 (0x7af) - AIF4TX2MIX Input 4 Volume */ + { 0x000007c0, 0x0000 }, /* R1984 (0x7c0) - SLIMTX1MIX Input 1 Source */ + { 0x000007c1, 0x0080 }, /* R1985 (0x7c1) - SLIMTX1MIX Input 1 Volume */ + { 0x000007c2, 0x0000 }, /* R1986 (0x7c2) - SLIMTX1MIX Input 2 Source */ + { 0x000007c3, 0x0080 }, /* R1987 (0x7c3) - SLIMTX1MIX Input 2 Volume */ + { 0x000007c4, 0x0000 }, /* R1988 (0x7c4) - SLIMTX1MIX Input 3 Source */ + { 0x000007c5, 0x0080 }, /* R1989 (0x7c5) - SLIMTX1MIX Input 3 Volume */ + { 0x000007c6, 0x0000 }, /* R1990 (0x7c6) - SLIMTX1MIX Input 4 Source */ + { 0x000007c7, 0x0080 }, /* R1991 (0x7c7) - SLIMTX1MIX Input 4 Volume */ + { 0x000007c8, 0x0000 }, /* R1992 (0x7c8) - SLIMTX2MIX Input 1 Source */ + { 0x000007c9, 0x0080 }, /* R1993 (0x7c9) - SLIMTX2MIX Input 1 Volume */ + { 0x000007ca, 0x0000 }, /* R1994 (0x7ca) - SLIMTX2MIX Input 2 Source */ + { 0x000007cb, 0x0080 }, /* R1995 (0x7cb) - SLIMTX2MIX Input 2 Volume */ + { 0x000007cc, 0x0000 }, /* R1996 (0x7cc) - SLIMTX2MIX Input 3 Source */ + { 0x000007cd, 0x0080 }, /* R1997 (0x7cd) - SLIMTX2MIX Input 3 Volume */ + { 0x000007ce, 0x0000 }, /* R1998 (0x7ce) - SLIMTX2MIX Input 4 Source */ + { 0x000007cf, 0x0080 }, /* R1999 (0x7cf) - SLIMTX2MIX Input 4 Volume */ + { 0x000007d0, 0x0000 }, /* R2000 (0x7d0) - SLIMTX3MIX Input 1 Source */ + { 0x000007d1, 0x0080 }, /* R2001 (0x7d1) - SLIMTX3MIX Input 1 Volume */ + { 0x000007d2, 0x0000 }, /* R2002 (0x7d2) - SLIMTX3MIX Input 2 Source */ + { 0x000007d3, 0x0080 }, /* R2003 (0x7d3) - SLIMTX3MIX Input 2 Volume */ + { 0x000007d4, 0x0000 }, /* R2004 (0x7d4) - SLIMTX3MIX Input 3 Source */ + { 0x000007d5, 0x0080 }, /* R2005 (0x7d5) - SLIMTX3MIX Input 3 Volume */ + { 0x000007d6, 0x0000 }, /* R2006 (0x7d6) - SLIMTX3MIX Input 4 Source */ + { 0x000007d7, 0x0080 }, /* R2007 (0x7d7) - SLIMTX3MIX Input 4 Volume */ + { 0x000007d8, 0x0000 }, /* R2008 (0x7d8) - SLIMTX4MIX Input 1 Source */ + { 0x000007d9, 0x0080 }, /* R2009 (0x7d9) - SLIMTX4MIX Input 1 Volume */ + { 0x000007da, 0x0000 }, /* R2010 (0x7da) - SLIMTX4MIX Input 2 Source */ + { 0x000007db, 0x0080 }, /* R2011 (0x7db) - SLIMTX4MIX Input 2 Volume */ + { 0x000007dc, 0x0000 }, /* R2012 (0x7dc) - SLIMTX4MIX Input 3 Source */ + { 0x000007dd, 0x0080 }, /* R2013 (0x7dd) - SLIMTX4MIX Input 3 Volume */ + { 0x000007de, 0x0000 }, /* R2014 (0x7de) - SLIMTX4MIX Input 4 Source */ + { 0x000007df, 0x0080 }, /* R2015 (0x7df) - SLIMTX4MIX Input 4 Volume */ + { 0x000007e0, 0x0000 }, /* R2016 (0x7e0) - SLIMTX5MIX Input 1 Source */ + { 0x000007e1, 0x0080 }, /* R2017 (0x7e1) - SLIMTX5MIX Input 1 Volume */ + { 0x000007e2, 0x0000 }, /* R2018 (0x7e2) - SLIMTX5MIX Input 2 Source */ + { 0x000007e3, 0x0080 }, /* R2019 (0x7e3) - SLIMTX5MIX Input 2 Volume */ + { 0x000007e4, 0x0000 }, /* R2020 (0x7e4) - SLIMTX5MIX Input 3 Source */ + { 0x000007e5, 0x0080 }, /* R2021 (0x7e5) - SLIMTX5MIX Input 3 Volume */ + { 0x000007e6, 0x0000 }, /* R2022 (0x7e6) - SLIMTX5MIX Input 4 Source */ + { 0x000007e7, 0x0080 }, /* R2023 (0x7e7) - SLIMTX5MIX Input 4 Volume */ + { 0x000007e8, 0x0000 }, /* R2024 (0x7e8) - SLIMTX6MIX Input 1 Source */ + { 0x000007e9, 0x0080 }, /* R2025 (0x7e9) - SLIMTX6MIX Input 1 Volume */ + { 0x000007ea, 0x0000 }, /* R2026 (0x7ea) - SLIMTX6MIX Input 2 Source */ + { 0x000007eb, 0x0080 }, /* R2027 (0x7eb) - SLIMTX6MIX Input 2 Volume */ + { 0x000007ec, 0x0000 }, /* R2028 (0x7ec) - SLIMTX6MIX Input 3 Source */ + { 0x000007ed, 0x0080 }, /* R2029 (0x7ed) - SLIMTX6MIX Input 3 Volume */ + { 0x000007ee, 0x0000 }, /* R2030 (0x7ee) - SLIMTX6MIX Input 4 Source */ + { 0x000007ef, 0x0080 }, /* R2031 (0x7ef) - SLIMTX6MIX Input 4 Volume */ + { 0x000007f0, 0x0000 }, /* R2032 (0x7f0) - SLIMTX7MIX Input 1 Source */ + { 0x000007f1, 0x0080 }, /* R2033 (0x7f1) - SLIMTX7MIX Input 1 Volume */ + { 0x000007f2, 0x0000 }, /* R2034 (0x7f2) - SLIMTX7MIX Input 2 Source */ + { 0x000007f3, 0x0080 }, /* R2035 (0x7f3) - SLIMTX7MIX Input 2 Volume */ + { 0x000007f4, 0x0000 }, /* R2036 (0x7f4) - SLIMTX7MIX Input 3 Source */ + { 0x000007f5, 0x0080 }, /* R2037 (0x7f5) - SLIMTX7MIX Input 3 Volume */ + { 0x000007f6, 0x0000 }, /* R2038 (0x7f6) - SLIMTX7MIX Input 4 Source */ + { 0x000007f7, 0x0080 }, /* R2039 (0x7f7) - SLIMTX7MIX Input 4 Volume */ + { 0x000007f8, 0x0000 }, /* R2040 (0x7f8) - SLIMTX8MIX Input 1 Source */ + { 0x000007f9, 0x0080 }, /* R2041 (0x7f9) - SLIMTX8MIX Input 1 Volume */ + { 0x000007fa, 0x0000 }, /* R2042 (0x7fa) - SLIMTX8MIX Input 2 Source */ + { 0x000007fb, 0x0080 }, /* R2043 (0x7fb) - SLIMTX8MIX Input 2 Volume */ + { 0x000007fc, 0x0000 }, /* R2044 (0x7fc) - SLIMTX8MIX Input 3 Source */ + { 0x000007fd, 0x0080 }, /* R2045 (0x7fd) - SLIMTX8MIX Input 3 Volume */ + { 0x000007fe, 0x0000 }, /* R2046 (0x7fe) - SLIMTX8MIX Input 4 Source */ + { 0x000007ff, 0x0080 }, /* R2047 (0x7ff) - SLIMTX8MIX Input 4 Volume */ + { 0x00000800, 0x0000 }, /* R2048 (0x800) - SPDIF1TX1MIX Input 1 Source */ + { 0x00000801, 0x0080 }, /* R2049 (0x801) - SPDIF1TX1MIX Input 1 Volume */ + { 0x00000808, 0x0000 }, /* R2056 (0x808) - SPDIF1TX2MIX Input 1 Source */ + { 0x00000809, 0x0080 }, /* R2057 (0x809) - SPDIF1TX2MIX Input 1 Volume */ + { 0x00000880, 0x0000 }, /* R2176 (0x880) - EQ1MIX Input 1 Source */ + { 0x00000881, 0x0080 }, /* R2177 (0x881) - EQ1MIX Input 1 Volume */ + { 0x00000882, 0x0000 }, /* R2178 (0x882) - EQ1MIX Input 2 Source */ + { 0x00000883, 0x0080 }, /* R2179 (0x883) - EQ1MIX Input 2 Volume */ + { 0x00000884, 0x0000 }, /* R2180 (0x884) - EQ1MIX Input 3 Source */ + { 0x00000885, 0x0080 }, /* R2181 (0x885) - EQ1MIX Input 3 Volume */ + { 0x00000886, 0x0000 }, /* R2182 (0x886) - EQ1MIX Input 4 Source */ + { 0x00000887, 0x0080 }, /* R2183 (0x887) - EQ1MIX Input 4 Volume */ + { 0x00000888, 0x0000 }, /* R2184 (0x888) - EQ2MIX Input 1 Source */ + { 0x00000889, 0x0080 }, /* R2185 (0x889) - EQ2MIX Input 1 Volume */ + { 0x0000088a, 0x0000 }, /* R2186 (0x88a) - EQ2MIX Input 2 Source */ + { 0x0000088b, 0x0080 }, /* R2187 (0x88b) - EQ2MIX Input 2 Volume */ + { 0x0000088c, 0x0000 }, /* R2188 (0x88c) - EQ2MIX Input 3 Source */ + { 0x0000088d, 0x0080 }, /* R2189 (0x88d) - EQ2MIX Input 3 Volume */ + { 0x0000088e, 0x0000 }, /* R2190 (0x88e) - EQ2MIX Input 4 Source */ + { 0x0000088f, 0x0080 }, /* R2191 (0x88f) - EQ2MIX Input 4 Volume */ + { 0x00000890, 0x0000 }, /* R2192 (0x890) - EQ3MIX Input 1 Source */ + { 0x00000891, 0x0080 }, /* R2193 (0x891) - EQ3MIX Input 1 Volume */ + { 0x00000892, 0x0000 }, /* R2194 (0x892) - EQ3MIX Input 2 Source */ + { 0x00000893, 0x0080 }, /* R2195 (0x893) - EQ3MIX Input 2 Volume */ + { 0x00000894, 0x0000 }, /* R2196 (0x894) - EQ3MIX Input 3 Source */ + { 0x00000895, 0x0080 }, /* R2197 (0x895) - EQ3MIX Input 3 Volume */ + { 0x00000896, 0x0000 }, /* R2198 (0x896) - EQ3MIX Input 4 Source */ + { 0x00000897, 0x0080 }, /* R2199 (0x897) - EQ3MIX Input 4 Volume */ + { 0x00000898, 0x0000 }, /* R2200 (0x898) - EQ4MIX Input 1 Source */ + { 0x00000899, 0x0080 }, /* R2201 (0x899) - EQ4MIX Input 1 Volume */ + { 0x0000089a, 0x0000 }, /* R2202 (0x89a) - EQ4MIX Input 2 Source */ + { 0x0000089b, 0x0080 }, /* R2203 (0x89b) - EQ4MIX Input 2 Volume */ + { 0x0000089c, 0x0000 }, /* R2204 (0x89c) - EQ4MIX Input 3 Source */ + { 0x0000089d, 0x0080 }, /* R2205 (0x89d) - EQ4MIX Input 3 Volume */ + { 0x0000089e, 0x0000 }, /* R2206 (0x89e) - EQ4MIX Input 4 Source */ + { 0x0000089f, 0x0080 }, /* R2207 (0x89f) - EQ4MIX Input 4 Volume */ + { 0x000008c0, 0x0000 }, /* R2240 (0x8c0) - DRC1LMIX Input 1 Source */ + { 0x000008c1, 0x0080 }, /* R2241 (0x8c1) - DRC1LMIX Input 1 Volume */ + { 0x000008c2, 0x0000 }, /* R2242 (0x8c2) - DRC1LMIX Input 2 Source */ + { 0x000008c3, 0x0080 }, /* R2243 (0x8c3) - DRC1LMIX Input 2 Volume */ + { 0x000008c4, 0x0000 }, /* R2244 (0x8c4) - DRC1LMIX Input 3 Source */ + { 0x000008c5, 0x0080 }, /* R2245 (0x8c5) - DRC1LMIX Input 3 Volume */ + { 0x000008c6, 0x0000 }, /* R2246 (0x8c6) - DRC1LMIX Input 4 Source */ + { 0x000008c7, 0x0080 }, /* R2247 (0x8c7) - DRC1LMIX Input 4 Volume */ + { 0x000008c8, 0x0000 }, /* R2248 (0x8c8) - DRC1RMIX Input 1 Source */ + { 0x000008c9, 0x0080 }, /* R2249 (0x8c9) - DRC1RMIX Input 1 Volume */ + { 0x000008ca, 0x0000 }, /* R2250 (0x8ca) - DRC1RMIX Input 2 Source */ + { 0x000008cb, 0x0080 }, /* R2251 (0x8cb) - DRC1RMIX Input 2 Volume */ + { 0x000008cc, 0x0000 }, /* R2252 (0x8cc) - DRC1RMIX Input 3 Source */ + { 0x000008cd, 0x0080 }, /* R2253 (0x8cd) - DRC1RMIX Input 3 Volume */ + { 0x000008ce, 0x0000 }, /* R2254 (0x8ce) - DRC1RMIX Input 4 Source */ + { 0x000008cf, 0x0080 }, /* R2255 (0x8cf) - DRC1RMIX Input 4 Volume */ + { 0x000008d0, 0x0000 }, /* R2256 (0x8d0) - DRC2LMIX Input 1 Source */ + { 0x000008d1, 0x0080 }, /* R2257 (0x8d1) - DRC2LMIX Input 1 Volume */ + { 0x000008d2, 0x0000 }, /* R2258 (0x8d2) - DRC2LMIX Input 2 Source */ + { 0x000008d3, 0x0080 }, /* R2259 (0x8d3) - DRC2LMIX Input 2 Volume */ + { 0x000008d4, 0x0000 }, /* R2260 (0x8d4) - DRC2LMIX Input 3 Source */ + { 0x000008d5, 0x0080 }, /* R2261 (0x8d5) - DRC2LMIX Input 3 Volume */ + { 0x000008d6, 0x0000 }, /* R2262 (0x8d6) - DRC2LMIX Input 4 Source */ + { 0x000008d7, 0x0080 }, /* R2263 (0x8d7) - DRC2LMIX Input 4 Volume */ + { 0x000008d8, 0x0000 }, /* R2264 (0x8d8) - DRC2RMIX Input 1 Source */ + { 0x000008d9, 0x0080 }, /* R2265 (0x8d9) - DRC2RMIX Input 1 Volume */ + { 0x000008da, 0x0000 }, /* R2266 (0x8da) - DRC2RMIX Input 2 Source */ + { 0x000008db, 0x0080 }, /* R2267 (0x8db) - DRC2RMIX Input 2 Volume */ + { 0x000008dc, 0x0000 }, /* R2268 (0x8dc) - DRC2RMIX Input 3 Source */ + { 0x000008dd, 0x0080 }, /* R2269 (0x8dd) - DRC2RMIX Input 3 Volume */ + { 0x000008de, 0x0000 }, /* R2270 (0x8de) - DRC2RMIX Input 4 Source */ + { 0x000008df, 0x0080 }, /* R2271 (0x8df) - DRC2RMIX Input 4 Volume */ + { 0x00000900, 0x0000 }, /* R2304 (0x900) - HPLP1MIX Input 1 Source */ + { 0x00000901, 0x0080 }, /* R2305 (0x901) - HPLP1MIX Input 1 Volume */ + { 0x00000902, 0x0000 }, /* R2306 (0x902) - HPLP1MIX Input 2 Source */ + { 0x00000903, 0x0080 }, /* R2307 (0x903) - HPLP1MIX Input 2 Volume */ + { 0x00000904, 0x0000 }, /* R2308 (0x904) - HPLP1MIX Input 3 Source */ + { 0x00000905, 0x0080 }, /* R2309 (0x905) - HPLP1MIX Input 3 Volume */ + { 0x00000906, 0x0000 }, /* R2310 (0x906) - HPLP1MIX Input 4 Source */ + { 0x00000907, 0x0080 }, /* R2311 (0x907) - HPLP1MIX Input 4 Volume */ + { 0x00000908, 0x0000 }, /* R2312 (0x908) - HPLP2MIX Input 1 Source */ + { 0x00000909, 0x0080 }, /* R2313 (0x909) - HPLP2MIX Input 1 Volume */ + { 0x0000090a, 0x0000 }, /* R2314 (0x90a) - HPLP2MIX Input 2 Source */ + { 0x0000090b, 0x0080 }, /* R2315 (0x90b) - HPLP2MIX Input 2 Volume */ + { 0x0000090c, 0x0000 }, /* R2316 (0x90c) - HPLP2MIX Input 3 Source */ + { 0x0000090d, 0x0080 }, /* R2317 (0x90d) - HPLP2MIX Input 3 Volume */ + { 0x0000090e, 0x0000 }, /* R2318 (0x90e) - HPLP2MIX Input 4 Source */ + { 0x0000090f, 0x0080 }, /* R2319 (0x90f) - HPLP2MIX Input 4 Volume */ + { 0x00000910, 0x0000 }, /* R2320 (0x910) - HPLP3MIX Input 1 Source */ + { 0x00000911, 0x0080 }, /* R2321 (0x911) - HPLP3MIX Input 1 Volume */ + { 0x00000912, 0x0000 }, /* R2322 (0x912) - HPLP3MIX Input 2 Source */ + { 0x00000913, 0x0080 }, /* R2323 (0x913) - HPLP3MIX Input 2 Volume */ + { 0x00000914, 0x0000 }, /* R2324 (0x914) - HPLP3MIX Input 3 Source */ + { 0x00000915, 0x0080 }, /* R2325 (0x915) - HPLP3MIX Input 3 Volume */ + { 0x00000916, 0x0000 }, /* R2326 (0x916) - HPLP3MIX Input 4 Source */ + { 0x00000917, 0x0080 }, /* R2327 (0x917) - HPLP3MIX Input 4 Volume */ + { 0x00000918, 0x0000 }, /* R2328 (0x918) - HPLP4MIX Input 1 Source */ + { 0x00000919, 0x0080 }, /* R2329 (0x919) - HPLP4MIX Input 1 Volume */ + { 0x0000091a, 0x0000 }, /* R2330 (0x91a) - HPLP4MIX Input 2 Source */ + { 0x0000091b, 0x0080 }, /* R2331 (0x91b) - HPLP4MIX Input 2 Volume */ + { 0x0000091c, 0x0000 }, /* R2332 (0x91c) - HPLP4MIX Input 3 Source */ + { 0x0000091d, 0x0080 }, /* R2333 (0x91d) - HPLP4MIX Input 3 Volume */ + { 0x0000091e, 0x0000 }, /* R2334 (0x91e) - HPLP4MIX Input 4 Source */ + { 0x0000091f, 0x0080 }, /* R2335 (0x91f) - HPLP4MIX Input 4 Volume */ + { 0x00000940, 0x0000 }, /* R2368 (0x940) - DSP1LMIX Input 1 Source */ + { 0x00000941, 0x0080 }, /* R2369 (0x941) - DSP1LMIX Input 1 Volume */ + { 0x00000942, 0x0000 }, /* R2370 (0x942) - DSP1LMIX Input 2 Source */ + { 0x00000943, 0x0080 }, /* R2371 (0x943) - DSP1LMIX Input 2 Volume */ + { 0x00000944, 0x0000 }, /* R2372 (0x944) - DSP1LMIX Input 3 Source */ + { 0x00000945, 0x0080 }, /* R2373 (0x945) - DSP1LMIX Input 3 Volume */ + { 0x00000946, 0x0000 }, /* R2374 (0x946) - DSP1LMIX Input 4 Source */ + { 0x00000947, 0x0080 }, /* R2375 (0x947) - DSP1LMIX Input 4 Volume */ + { 0x00000948, 0x0000 }, /* R2376 (0x948) - DSP1RMIX Input 1 Source */ + { 0x00000949, 0x0080 }, /* R2377 (0x949) - DSP1RMIX Input 1 Volume */ + { 0x0000094a, 0x0000 }, /* R2378 (0x94a) - DSP1RMIX Input 2 Source */ + { 0x0000094b, 0x0080 }, /* R2379 (0x94b) - DSP1RMIX Input 2 Volume */ + { 0x0000094c, 0x0000 }, /* R2380 (0x94c) - DSP1RMIX Input 3 Source */ + { 0x0000094d, 0x0080 }, /* R2381 (0x94d) - DSP1RMIX Input 3 Volume */ + { 0x0000094e, 0x0000 }, /* R2382 (0x94e) - DSP1RMIX Input 4 Source */ + { 0x0000094f, 0x0080 }, /* R2383 (0x94f) - DSP1RMIX Input 4 Volume */ + { 0x00000950, 0x0000 }, /* R2384 (0x950) - DSP1AUX1MIX Input 1 Source */ + { 0x00000958, 0x0000 }, /* R2392 (0x958) - DSP1AUX2MIX Input 1 Source */ + { 0x00000960, 0x0000 }, /* R2400 (0x960) - DSP1AUX3MIX Input 1 Source */ + { 0x00000968, 0x0000 }, /* R2408 (0x968) - DSP1AUX4MIX Input 1 Source */ + { 0x00000970, 0x0000 }, /* R2416 (0x970) - DSP1AUX5MIX Input 1 Source */ + { 0x00000978, 0x0000 }, /* R2424 (0x978) - DSP1AUX6MIX Input 1 Source */ + { 0x00000980, 0x0000 }, /* R2432 (0x980) - DSP2LMIX Input 1 Source */ + { 0x00000981, 0x0080 }, /* R2433 (0x981) - DSP2LMIX Input 1 Volume */ + { 0x00000982, 0x0000 }, /* R2434 (0x982) - DSP2LMIX Input 2 Source */ + { 0x00000983, 0x0080 }, /* R2435 (0x983) - DSP2LMIX Input 2 Volume */ + { 0x00000984, 0x0000 }, /* R2436 (0x984) - DSP2LMIX Input 3 Source */ + { 0x00000985, 0x0080 }, /* R2437 (0x985) - DSP2LMIX Input 3 Volume */ + { 0x00000986, 0x0000 }, /* R2438 (0x986) - DSP2LMIX Input 4 Source */ + { 0x00000987, 0x0080 }, /* R2439 (0x987) - DSP2LMIX Input 4 Volume */ + { 0x00000988, 0x0000 }, /* R2440 (0x988) - DSP2RMIX Input 1 Source */ + { 0x00000989, 0x0080 }, /* R2441 (0x989) - DSP2RMIX Input 1 Volume */ + { 0x0000098a, 0x0000 }, /* R2442 (0x98a) - DSP2RMIX Input 2 Source */ + { 0x0000098b, 0x0080 }, /* R2443 (0x98b) - DSP2RMIX Input 2 Volume */ + { 0x0000098c, 0x0000 }, /* R2444 (0x98c) - DSP2RMIX Input 3 Source */ + { 0x0000098d, 0x0080 }, /* R2445 (0x98d) - DSP2RMIX Input 3 Volume */ + { 0x0000098e, 0x0000 }, /* R2446 (0x98e) - DSP2RMIX Input 4 Source */ + { 0x0000098f, 0x0080 }, /* R2447 (0x98f) - DSP2RMIX Input 4 Volume */ + { 0x00000990, 0x0000 }, /* R2448 (0x990) - DSP2AUX1MIX Input 1 Source */ + { 0x00000998, 0x0000 }, /* R2456 (0x998) - DSP2AUX2MIX Input 1 Source */ + { 0x000009a0, 0x0000 }, /* R2464 (0x9a0) - DSP2AUX3MIX Input 1 Source */ + { 0x000009a8, 0x0000 }, /* R2472 (0x9a8) - DSP2AUX4MIX Input 1 Source */ + { 0x000009b0, 0x0000 }, /* R2480 (0x9b0) - DSP2AUX5MIX Input 1 Source */ + { 0x000009b8, 0x0000 }, /* R2488 (0x9b8) - DSP2AUX6MIX Input 1 Source */ + { 0x000009c0, 0x0000 }, /* R2496 (0x9c0) - DSP3LMIX Input 1 Source */ + { 0x000009c1, 0x0080 }, /* R2497 (0x9c1) - DSP3LMIX Input 1 Volume */ + { 0x000009c2, 0x0000 }, /* R2498 (0x9c2) - DSP3LMIX Input 2 Source */ + { 0x000009c3, 0x0080 }, /* R2499 (0x9c3) - DSP3LMIX Input 2 Volume */ + { 0x000009c4, 0x0000 }, /* R2500 (0x9c4) - DSP3LMIX Input 3 Source */ + { 0x000009c5, 0x0080 }, /* R2501 (0x9c5) - DSP3LMIX Input 3 Volume */ + { 0x000009c6, 0x0000 }, /* R2502 (0x9c6) - DSP3LMIX Input 4 Source */ + { 0x000009c7, 0x0080 }, /* R2503 (0x9c7) - DSP3LMIX Input 4 Volume */ + { 0x000009c8, 0x0000 }, /* R2504 (0x9c8) - DSP3RMIX Input 1 Source */ + { 0x000009c9, 0x0080 }, /* R2505 (0x9c9) - DSP3RMIX Input 1 Volume */ + { 0x000009ca, 0x0000 }, /* R2506 (0x9ca) - DSP3RMIX Input 2 Source */ + { 0x000009cb, 0x0080 }, /* R2507 (0x9cb) - DSP3RMIX Input 2 Volume */ + { 0x000009cc, 0x0000 }, /* R2508 (0x9cc) - DSP3RMIX Input 3 Source */ + { 0x000009cd, 0x0080 }, /* R2509 (0x9cd) - DSP3RMIX Input 3 Volume */ + { 0x000009ce, 0x0000 }, /* R2510 (0x9ce) - DSP3RMIX Input 4 Source */ + { 0x000009cf, 0x0080 }, /* R2511 (0x9cf) - DSP3RMIX Input 4 Volume */ + { 0x000009d0, 0x0000 }, /* R2512 (0x9d0) - DSP3AUX1MIX Input 1 Source */ + { 0x000009d8, 0x0000 }, /* R2520 (0x9d8) - DSP3AUX2MIX Input 1 Source */ + { 0x000009e0, 0x0000 }, /* R2528 (0x9e0) - DSP3AUX3MIX Input 1 Source */ + { 0x000009e8, 0x0000 }, /* R2536 (0x9e8) - DSP3AUX4MIX Input 1 Source */ + { 0x000009f0, 0x0000 }, /* R2544 (0x9f0) - DSP3AUX5MIX Input 1 Source */ + { 0x000009f8, 0x0000 }, /* R2552 (0x9f8) - DSP3AUX6MIX Input 1 Source */ + { 0x00000a00, 0x0000 }, /* R2560 (0xa00) - DSP4LMIX Input 1 Source */ + { 0x00000a01, 0x0080 }, /* R2561 (0xa01) - DSP4LMIX Input 1 Volume */ + { 0x00000a02, 0x0000 }, /* R2562 (0xa02) - DSP4LMIX Input 2 Source */ + { 0x00000a03, 0x0080 }, /* R2563 (0xa03) - DSP4LMIX Input 2 Volume */ + { 0x00000a04, 0x0000 }, /* R2564 (0xa04) - DSP4LMIX Input 3 Source */ + { 0x00000a05, 0x0080 }, /* R2565 (0xa05) - DSP4LMIX Input 3 Volume */ + { 0x00000a06, 0x0000 }, /* R2566 (0xa06) - DSP4LMIX Input 4 Source */ + { 0x00000a07, 0x0080 }, /* R2567 (0xa07) - DSP4LMIX Input 4 Volume */ + { 0x00000a08, 0x0000 }, /* R2568 (0xa08) - DSP4RMIX Input 1 Source */ + { 0x00000a09, 0x0080 }, /* R2569 (0xa09) - DSP4RMIX Input 1 Volume */ + { 0x00000a0a, 0x0000 }, /* R2570 (0xa0a) - DSP4RMIX Input 2 Source */ + { 0x00000a0b, 0x0080 }, /* R2571 (0xa0b) - DSP4RMIX Input 2 Volume */ + { 0x00000a0c, 0x0000 }, /* R2572 (0xa0c) - DSP4RMIX Input 3 Source */ + { 0x00000a0d, 0x0080 }, /* R2573 (0xa0d) - DSP4RMIX Input 3 Volume */ + { 0x00000a0e, 0x0000 }, /* R2574 (0xa0e) - DSP4RMIX Input 4 Source */ + { 0x00000a0f, 0x0080 }, /* R2575 (0xa0f) - DSP4RMIX Input 4 Volume */ + { 0x00000a10, 0x0000 }, /* R2576 (0xa10) - DSP4AUX1MIX Input 1 Source */ + { 0x00000a18, 0x0000 }, /* R2584 (0xa18) - DSP4AUX2MIX Input 1 Source */ + { 0x00000a20, 0x0000 }, /* R2592 (0xa20) - DSP4AUX3MIX Input 1 Source */ + { 0x00000a28, 0x0000 }, /* R2600 (0xa28) - DSP4AUX4MIX Input 1 Source */ + { 0x00000a30, 0x0000 }, /* R2608 (0xa30) - DSP4AUX5MIX Input 1 Source */ + { 0x00000a38, 0x0000 }, /* R2616 (0xa38) - DSP4AUX6MIX Input 1 Source */ + { 0x00000a40, 0x0000 }, /* R2624 (0xa40) - DSP5LMIX Input 1 Source */ + { 0x00000a41, 0x0080 }, /* R2625 (0xa41) - DSP5LMIX Input 1 Volume */ + { 0x00000a42, 0x0000 }, /* R2626 (0xa42) - DSP5LMIX Input 2 Source */ + { 0x00000a43, 0x0080 }, /* R2627 (0xa43) - DSP5LMIX Input 2 Volume */ + { 0x00000a44, 0x0000 }, /* R2628 (0xa44) - DSP5LMIX Input 3 Source */ + { 0x00000a45, 0x0080 }, /* R2629 (0xa45) - DSP5LMIX Input 3 Volume */ + { 0x00000a46, 0x0000 }, /* R2630 (0xa46) - DSP5LMIX Input 4 Source */ + { 0x00000a47, 0x0080 }, /* R2631 (0xa47) - DSP5LMIX Input 4 Volume */ + { 0x00000a48, 0x0000 }, /* R2632 (0xa48) - DSP5RMIX Input 1 Source */ + { 0x00000a49, 0x0080 }, /* R2633 (0xa49) - DSP5RMIX Input 1 Volume */ + { 0x00000a4a, 0x0000 }, /* R2634 (0xa4a) - DSP5RMIX Input 2 Source */ + { 0x00000a4b, 0x0080 }, /* R2635 (0xa4b) - DSP5RMIX Input 2 Volume */ + { 0x00000a4c, 0x0000 }, /* R2636 (0xa4c) - DSP5RMIX Input 3 Source */ + { 0x00000a4d, 0x0080 }, /* R2637 (0xa4d) - DSP5RMIX Input 3 Volume */ + { 0x00000a4e, 0x0000 }, /* R2638 (0xa4e) - DSP5RMIX Input 4 Source */ + { 0x00000a4f, 0x0080 }, /* R2639 (0xa4f) - DSP5RMIX Input 4 Volume */ + { 0x00000a50, 0x0000 }, /* R2640 (0xa50) - DSP5AUX1MIX Input 1 Source */ + { 0x00000a58, 0x0000 }, /* R2658 (0xa58) - DSP5AUX2MIX Input 1 Source */ + { 0x00000a60, 0x0000 }, /* R2656 (0xa60) - DSP5AUX3MIX Input 1 Source */ + { 0x00000a68, 0x0000 }, /* R2664 (0xa68) - DSP5AUX4MIX Input 1 Source */ + { 0x00000a70, 0x0000 }, /* R2672 (0xa70) - DSP5AUX5MIX Input 1 Source */ + { 0x00000a78, 0x0000 }, /* R2680 (0xa78) - DSP5AUX6MIX Input 1 Source */ + { 0x00000a80, 0x0000 }, /* R2688 (0xa80) - ASRC1_1LMIX Input 1 Source */ + { 0x00000a88, 0x0000 }, /* R2696 (0xa88) - ASRC1_1RMIX Input 1 Source */ + { 0x00000a90, 0x0000 }, /* R2704 (0xa90) - ASRC1_2LMIX Input 1 Source */ + { 0x00000a98, 0x0000 }, /* R2712 (0xa98) - ASRC1_2RMIX Input 1 Source */ + { 0x00000aa0, 0x0000 }, /* R2720 (0xaa0) - ASRC2_1LMIX Input 1 Source */ + { 0x00000aa8, 0x0000 }, /* R2728 (0xaa8) - ASRC2_1RMIX Input 1 Source */ + { 0x00000ab0, 0x0000 }, /* R2736 (0xab0) - ASRC2_2LMIX Input 1 Source */ + { 0x00000ab8, 0x0000 }, /* R2744 (0xab8) - ASRC2_2RMIX Input 1 Source */ + { 0x00000b00, 0x0000 }, /* R2816 (0xb00) - ISRC1DEC1MIX Input 1 Source*/ + { 0x00000b08, 0x0000 }, /* R2824 (0xb08) - ISRC1DEC2MIX Input 1 Source*/ + { 0x00000b10, 0x0000 }, /* R2832 (0xb10) - ISRC1DEC3MIX Input 1 Source*/ + { 0x00000b18, 0x0000 }, /* R2840 (0xb18) - ISRC1DEC4MIX Input 1 Source*/ + { 0x00000b20, 0x0000 }, /* R2848 (0xb20) - ISRC1INT1MIX Input 1 Source*/ + { 0x00000b28, 0x0000 }, /* R2856 (0xb28) - ISRC1INT2MIX Input 1 Source*/ + { 0x00000b30, 0x0000 }, /* R2864 (0xb30) - ISRC1INT3MIX Input 1 Source*/ + { 0x00000b38, 0x0000 }, /* R2872 (0xb38) - ISRC1INT4MIX Input 1 Source*/ + { 0x00000b40, 0x0000 }, /* R2880 (0xb40) - ISRC2DEC1MIX Input 1 Source*/ + { 0x00000b48, 0x0000 }, /* R2888 (0xb48) - ISRC2DEC2MIX Input 1 Source*/ + { 0x00000b50, 0x0000 }, /* R2896 (0xb50) - ISRC2DEC3MIX Input 1 Source*/ + { 0x00000b58, 0x0000 }, /* R2904 (0xb58) - ISRC2DEC4MIX Input 1 Source*/ + { 0x00000b60, 0x0000 }, /* R2912 (0xb60) - ISRC2INT1MIX Input 1 Source*/ + { 0x00000b68, 0x0000 }, /* R2920 (0xb68) - ISRC2INT2MIX Input 1 Source*/ + { 0x00000b70, 0x0000 }, /* R2928 (0xb70) - ISRC2INT3MIX Input 1 Source*/ + { 0x00000b78, 0x0000 }, /* R2936 (0xb78) - ISRC2INT4MIX Input 1 Source*/ + { 0x00000b80, 0x0000 }, /* R2944 (0xb80) - ISRC3DEC1MIX Input 1 Source*/ + { 0x00000b88, 0x0000 }, /* R2952 (0xb88) - ISRC3DEC2MIX Input 1 Source*/ + { 0x00000ba0, 0x0000 }, /* R2976 (0xb80) - ISRC3INT1MIX Input 1 Source*/ + { 0x00000ba8, 0x0000 }, /* R2984 (0xb88) - ISRC3INT2MIX Input 1 Source*/ + { 0x00000bc0, 0x0000 }, /* R3008 (0xbc0) - ISRC4DEC1MIX Input 1 Source */ + { 0x00000bc8, 0x0000 }, /* R3016 (0xbc8) - ISRC4DEC2MIX Input 1 Source */ + { 0x00000be0, 0x0000 }, /* R3040 (0xbe0) - ISRC4INT1MIX Input 1 Source */ + { 0x00000be8, 0x0000 }, /* R3048 (0xbe8) - ISRC4INT2MIX Input 1 Source */ + { 0x00000c00, 0x0000 }, /* R3072 (0xc00) - DSP6LMIX Input 1 Source */ + { 0x00000c01, 0x0080 }, /* R3073 (0xc01) - DSP6LMIX Input 1 Volume */ + { 0x00000c02, 0x0000 }, /* R3074 (0xc02) - DSP6LMIX Input 2 Source */ + { 0x00000c03, 0x0080 }, /* R3075 (0xc03) - DSP6LMIX Input 2 Volume */ + { 0x00000c04, 0x0000 }, /* R3076 (0xc04) - DSP6LMIX Input 3 Source */ + { 0x00000c05, 0x0080 }, /* R3077 (0xc05) - DSP6LMIX Input 3 Volume */ + { 0x00000c06, 0x0000 }, /* R3078 (0xc06) - DSP6LMIX Input 4 Source */ + { 0x00000c07, 0x0080 }, /* R3079 (0xc07) - DSP6LMIX Input 4 Volume */ + { 0x00000c08, 0x0000 }, /* R3080 (0xc08) - DSP6RMIX Input 1 Source */ + { 0x00000c09, 0x0080 }, /* R3081 (0xc09) - DSP6RMIX Input 1 Volume */ + { 0x00000c0a, 0x0000 }, /* R3082 (0xc0a) - DSP6RMIX Input 2 Source */ + { 0x00000c0b, 0x0080 }, /* R3083 (0xc0b) - DSP6RMIX Input 2 Volume */ + { 0x00000c0c, 0x0000 }, /* R3084 (0xc0c) - DSP6RMIX Input 3 Source */ + { 0x00000c0d, 0x0080 }, /* R3085 (0xc0d) - DSP6RMIX Input 3 Volume */ + { 0x00000c0e, 0x0000 }, /* R3086 (0xc0e) - DSP6RMIX Input 4 Source */ + { 0x00000c0f, 0x0080 }, /* R3087 (0xc0f) - DSP6RMIX Input 4 Volume */ + { 0x00000c10, 0x0000 }, /* R3088 (0xc10) - DSP6AUX1MIX Input 1 Source */ + { 0x00000c18, 0x0000 }, /* R3088 (0xc18) - DSP6AUX2MIX Input 1 Source */ + { 0x00000c20, 0x0000 }, /* R3088 (0xc20) - DSP6AUX3MIX Input 1 Source */ + { 0x00000c28, 0x0000 }, /* R3088 (0xc28) - DSP6AUX4MIX Input 1 Source */ + { 0x00000c30, 0x0000 }, /* R3088 (0xc30) - DSP6AUX5MIX Input 1 Source */ + { 0x00000c38, 0x0000 }, /* R3088 (0xc38) - DSP6AUX6MIX Input 1 Source */ + { 0x00000c40, 0x0000 }, /* R3136 (0xc40) - DSP7LMIX Input 1 Source */ + { 0x00000c41, 0x0080 }, /* R3137 (0xc41) - DSP7LMIX Input 1 Volume */ + { 0x00000c42, 0x0000 }, /* R3138 (0xc42) - DSP7LMIX Input 2 Source */ + { 0x00000c43, 0x0080 }, /* R3139 (0xc43) - DSP7LMIX Input 2 Volume */ + { 0x00000c44, 0x0000 }, /* R3140 (0xc44) - DSP7LMIX Input 3 Source */ + { 0x00000c45, 0x0080 }, /* R3141 (0xc45) - DSP7lMIX Input 3 Volume */ + { 0x00000c46, 0x0000 }, /* R3142 (0xc46) - DSP7lMIX Input 4 Source */ + { 0x00000c47, 0x0080 }, /* R3143 (0xc47) - DSP7LMIX Input 4 Volume */ + { 0x00000c48, 0x0000 }, /* R3144 (0xc48) - DSP7RMIX Input 1 Source */ + { 0x00000c49, 0x0080 }, /* R3145 (0xc49) - DSP7RMIX Input 1 Volume */ + { 0x00000c4a, 0x0000 }, /* R3146 (0xc4a) - DSP7RMIX Input 2 Source */ + { 0x00000c4b, 0x0080 }, /* R3147 (0xc4b) - DSP7RMIX Input 2 Volume */ + { 0x00000c4c, 0x0000 }, /* R3148 (0xc4c) - DSP7RMIX Input 3 Source */ + { 0x00000c4d, 0x0080 }, /* R3159 (0xc4d) - DSP7RMIX Input 3 Volume */ + { 0x00000c4e, 0x0000 }, /* R3150 (0xc4e) - DSP7RMIX Input 4 Source */ + { 0x00000c4f, 0x0080 }, /* R3151 (0xc4f) - DSP7RMIX Input 4 Volume */ + { 0x00000c50, 0x0000 }, /* R3152 (0xc50) - DSP7AUX1MIX Input 1 Source */ + { 0x00000c58, 0x0000 }, /* R3160 (0xc58) - DSP7AUX2MIX Input 1 Source */ + { 0x00000c60, 0x0000 }, /* R3168 (0xc60) - DSP7AUX3MIX Input 1 Source */ + { 0x00000c68, 0x0000 }, /* R3176 (0xc68) - DSP7AUX4MIX Input 1 Source */ + { 0x00000c70, 0x0000 }, /* R3184 (0xc70) - DSP7AUX5MIX Input 1 Source */ + { 0x00000c78, 0x0000 }, /* R3192 (0xc78) - DSP7AUX6MIX Input 1 Source */ + { 0x00000e00, 0x0000 }, /* R3584 (0xe00) - FX Ctrl1 */ + { 0x00000e10, 0x6318 }, /* R3600 (0xe10) - EQ1_1 */ + { 0x00000e11, 0x6300 }, /* R3601 (0xe11) - EQ1_2 */ + { 0x00000e12, 0x0fc8 }, /* R3602 (0xe12) - EQ1_3 */ + { 0x00000e13, 0x03fe }, /* R3603 (0xe13) - EQ1_4 */ + { 0x00000e14, 0x00e0 }, /* R3604 (0xe14) - EQ1_5 */ + { 0x00000e15, 0x1ec4 }, /* R3605 (0xe15) - EQ1_6 */ + { 0x00000e16, 0xf136 }, /* R3606 (0xe16) - EQ1_7 */ + { 0x00000e17, 0x0409 }, /* R3607 (0xe17) - EQ1_8 */ + { 0x00000e18, 0x04cc }, /* R3608 (0xe18) - EQ1_9 */ + { 0x00000e19, 0x1c9b }, /* R3609 (0xe19) - EQ1_10 */ + { 0x00000e1a, 0xf337 }, /* R3610 (0xe1a) - EQ1_11 */ + { 0x00000e1b, 0x040b }, /* R3611 (0xe1b) - EQ1_12 */ + { 0x00000e1c, 0x0cbb }, /* R3612 (0xe1c) - EQ1_13 */ + { 0x00000e1d, 0x16f8 }, /* R3613 (0xe1d) - EQ1_14 */ + { 0x00000e1e, 0xf7d9 }, /* R3614 (0xe1e) - EQ1_15 */ + { 0x00000e1f, 0x040a }, /* R3615 (0xe1f) - EQ1_16 */ + { 0x00000e20, 0x1f14 }, /* R3616 (0xe20) - EQ1_17 */ + { 0x00000e21, 0x058c }, /* R3617 (0xe21) - EQ1_18 */ + { 0x00000e22, 0x0563 }, /* R3618 (0xe22) - EQ1_19 */ + { 0x00000e23, 0x4000 }, /* R3619 (0xe23) - EQ1_20 */ + { 0x00000e24, 0x0b75 }, /* R3620 (0xe24) - EQ1_21 */ + { 0x00000e26, 0x6318 }, /* R3622 (0xe26) - EQ2_1 */ + { 0x00000e27, 0x6300 }, /* R3623 (0xe27) - EQ2_2 */ + { 0x00000e28, 0x0fc8 }, /* R3624 (0xe28) - EQ2_3 */ + { 0x00000e29, 0x03fe }, /* R3625 (0xe29) - EQ2_4 */ + { 0x00000e2a, 0x00e0 }, /* R3626 (0xe2a) - EQ2_5 */ + { 0x00000e2b, 0x1ec4 }, /* R3627 (0xe2b) - EQ2_6 */ + { 0x00000e2c, 0xf136 }, /* R3628 (0xe2c) - EQ2_7 */ + { 0x00000e2d, 0x0409 }, /* R3629 (0xe2d) - EQ2_8 */ + { 0x00000e2e, 0x04cc }, /* R3630 (0xe2e) - EQ2_9 */ + { 0x00000e2f, 0x1c9b }, /* R3631 (0xe2f) - EQ2_10 */ + { 0x00000e30, 0xf337 }, /* R3632 (0xe30) - EQ2_11 */ + { 0x00000e31, 0x040b }, /* R3633 (0xe31) - EQ2_12 */ + { 0x00000e32, 0x0cbb }, /* R3634 (0xe32) - EQ2_13 */ + { 0x00000e33, 0x16f8 }, /* R3635 (0xe33) - EQ2_14 */ + { 0x00000e34, 0xf7d9 }, /* R3636 (0xe34) - EQ2_15 */ + { 0x00000e35, 0x040a }, /* R3637 (0xe35) - EQ2_16 */ + { 0x00000e36, 0x1f14 }, /* R3638 (0xe36) - EQ2_17 */ + { 0x00000e37, 0x058c }, /* R3639 (0xe37) - EQ2_18 */ + { 0x00000e38, 0x0563 }, /* R3640 (0xe38) - EQ2_19 */ + { 0x00000e39, 0x4000 }, /* R3641 (0xe39) - EQ2_20 */ + { 0x00000e3a, 0x0b75 }, /* R3642 (0xe3a) - EQ2_21 */ + { 0x00000e3c, 0x6318 }, /* R3644 (0xe3c) - EQ3_1 */ + { 0x00000e3d, 0x6300 }, /* R3645 (0xe3d) - EQ3_2 */ + { 0x00000e3e, 0x0fc8 }, /* R3646 (0xe3e) - EQ3_3 */ + { 0x00000e3f, 0x03fe }, /* R3647 (0xe3f) - EQ3_4 */ + { 0x00000e40, 0x00e0 }, /* R3648 (0xe40) - EQ3_5 */ + { 0x00000e41, 0x1ec4 }, /* R3649 (0xe41) - EQ3_6 */ + { 0x00000e42, 0xf136 }, /* R3650 (0xe42) - EQ3_7 */ + { 0x00000e43, 0x0409 }, /* R3651 (0xe43) - EQ3_8 */ + { 0x00000e44, 0x04cc }, /* R3652 (0xe44) - EQ3_9 */ + { 0x00000e45, 0x1c9b }, /* R3653 (0xe45) - EQ3_10 */ + { 0x00000e46, 0xf337 }, /* R3654 (0xe46) - EQ3_11 */ + { 0x00000e47, 0x040b }, /* R3655 (0xe47) - EQ3_12 */ + { 0x00000e48, 0x0cbb }, /* R3656 (0xe48) - EQ3_13 */ + { 0x00000e49, 0x16f8 }, /* R3657 (0xe49) - EQ3_14 */ + { 0x00000e4a, 0xf7d9 }, /* R3658 (0xe4a) - EQ3_15 */ + { 0x00000e4b, 0x040a }, /* R3659 (0xe4b) - EQ3_16 */ + { 0x00000e4c, 0x1f14 }, /* R3660 (0xe4c) - EQ3_17 */ + { 0x00000e4d, 0x058c }, /* R3661 (0xe4d) - EQ3_18 */ + { 0x00000e4e, 0x0563 }, /* R3662 (0xe4e) - EQ3_19 */ + { 0x00000e4f, 0x4000 }, /* R3663 (0xe4f) - EQ3_20 */ + { 0x00000e50, 0x0b75 }, /* R3664 (0xe50) - EQ3_21 */ + { 0x00000e52, 0x6318 }, /* R3666 (0xe52) - EQ4_1 */ + { 0x00000e53, 0x6300 }, /* R3667 (0xe53) - EQ4_2 */ + { 0x00000e54, 0x0fc8 }, /* R3668 (0xe54) - EQ4_3 */ + { 0x00000e55, 0x03fe }, /* R3669 (0xe55) - EQ4_4 */ + { 0x00000e56, 0x00e0 }, /* R3670 (0xe56) - EQ4_5 */ + { 0x00000e57, 0x1ec4 }, /* R3671 (0xe57) - EQ4_6 */ + { 0x00000e58, 0xf136 }, /* R3672 (0xe58) - EQ4_7 */ + { 0x00000e59, 0x0409 }, /* R3673 (0xe59) - EQ4_8 */ + { 0x00000e5a, 0x04cc }, /* R3674 (0xe5a) - EQ4_9 */ + { 0x00000e5b, 0x1c9b }, /* R3675 (0xe5b) - EQ4_10 */ + { 0x00000e5c, 0xf337 }, /* R3676 (0xe5c) - EQ4_11 */ + { 0x00000e5d, 0x040b }, /* R3677 (0xe5d) - EQ4_12 */ + { 0x00000e5e, 0x0cbb }, /* R3678 (0xe5e) - EQ4_13 */ + { 0x00000e5f, 0x16f8 }, /* R3679 (0xe5f) - EQ4_14 */ + { 0x00000e60, 0xf7d9 }, /* R3680 (0xe60) - EQ4_15 */ + { 0x00000e61, 0x040a }, /* R3681 (0xe61) - EQ4_16 */ + { 0x00000e62, 0x1f14 }, /* R3682 (0xe62) - EQ4_17 */ + { 0x00000e63, 0x058c }, /* R3683 (0xe63) - EQ4_18 */ + { 0x00000e64, 0x0563 }, /* R3684 (0xe64) - EQ4_19 */ + { 0x00000e65, 0x4000 }, /* R3685 (0xe65) - EQ4_20 */ + { 0x00000e66, 0x0b75 }, /* R3686 (0xe66) - EQ4_21 */ + { 0x00000e80, 0x0018 }, /* R3712 (0xe80) - DRC1 ctrl1 */ + { 0x00000e81, 0x0933 }, /* R3713 (0xe81) - DRC1 ctrl2 */ + { 0x00000e82, 0x0018 }, /* R3714 (0xe82) - DRC1 ctrl3 */ + { 0x00000e83, 0x0000 }, /* R3715 (0xe83) - DRC1 ctrl4 */ + { 0x00000e84, 0x0000 }, /* R3716 (0xe84) - DRC1 ctrl5 */ + { 0x00000e88, 0x0933 }, /* R3720 (0xe88) - DRC2 ctrl1 */ + { 0x00000e89, 0x0018 }, /* R3721 (0xe89) - DRC2 ctrl2 */ + { 0x00000e8a, 0x0000 }, /* R3722 (0xe8a) - DRC2 ctrl3 */ + { 0x00000e8b, 0x0000 }, /* R3723 (0xe8b) - DRC2 ctrl4 */ + { 0x00000e8c, 0x0040 }, /* R3724 (0xe8c) - DRC2 ctrl5 */ + { 0x00000ec0, 0x0000 }, /* R3776 (0xec0) - HPLPF1_1 */ + { 0x00000ec1, 0x0000 }, /* R3777 (0xec1) - HPLPF1_2 */ + { 0x00000ec4, 0x0000 }, /* R3780 (0xec4) - HPLPF2_1 */ + { 0x00000ec5, 0x0000 }, /* R3781 (0xec5) - HPLPF2_2 */ + { 0x00000ec8, 0x0000 }, /* R3784 (0xec8) - HPLPF3_1 */ + { 0x00000ec9, 0x0000 }, /* R3785 (0xec9) - HPLPF3_2 */ + { 0x00000ecc, 0x0000 }, /* R3788 (0xecc) - HPLPF4_1 */ + { 0x00000ecd, 0x0000 }, /* R3789 (0xecd) - HPLPF4_2 */ + { 0x00000ed0, 0x0000 }, /* R3792 (0xed0) - ASRC2_ENABLE */ + { 0x00000ed2, 0x0000 }, /* R3794 (0xed2) - ASRC2_RATE1 */ + { 0x00000ed3, 0x4000 }, /* R3795 (0xed3) - ASRC2_RATE2 */ + { 0x00000ee0, 0x0000 }, /* R3808 (0xee0) - ASRC1_ENABLE */ + { 0x00000ee2, 0x0000 }, /* R3810 (0xee2) - ASRC1_RATE1 */ + { 0x00000ee3, 0x4000 }, /* R3811 (0xee3) - ASRC1_RATE2 */ + { 0x00000ef0, 0x0000 }, /* R3824 (0xef0) - ISRC 1 CTRL 1 */ + { 0x00000ef1, 0x0001 }, /* R3825 (0xef1) - ISRC 1 CTRL 2 */ + { 0x00000ef2, 0x0000 }, /* R3826 (0xef2) - ISRC 1 CTRL 3 */ + { 0x00000ef3, 0x0000 }, /* R3827 (0xef3) - ISRC 2 CTRL 1 */ + { 0x00000ef4, 0x0001 }, /* R3828 (0xef4) - ISRC 2 CTRL 2 */ + { 0x00000ef5, 0x0000 }, /* R3829 (0xef5) - ISRC 2 CTRL 3 */ + { 0x00000ef6, 0x0000 }, /* R3830 (0xef6) - ISRC 3 CTRL 1 */ + { 0x00000ef7, 0x0001 }, /* R3831 (0xef7) - ISRC 3 CTRL 2 */ + { 0x00000ef8, 0x0000 }, /* R3832 (0xef8) - ISRC 3 CTRL 3 */ + { 0x00000ef9, 0x0000 }, /* R3833 (0xef9) - ISRC 4 CTRL 1 */ + { 0x00000efa, 0x0001 }, /* R3834 (0xefa) - ISRC 4 CTRL 2 */ + { 0x00000efb, 0x0000 }, /* R3835 (0xefb) - ISRC 4 CTRL 3 */ + { 0x00000f01, 0x0000 }, /* R3841 (0xf01) - ANC_SRC */ + { 0x00000f02, 0x0000 }, /* R3842 (0xf02) - DSP Status */ + { 0x00000f08, 0x001c }, /* R3848 (0xf08) - ANC Coefficient */ + { 0x00000f09, 0x0000 }, /* R3849 (0xf09) - ANC Coefficient */ + { 0x00000f0a, 0x0000 }, /* R3850 (0xf0a) - ANC Coefficient */ + { 0x00000f0b, 0x0000 }, /* R3851 (0xf0b) - ANC Coefficient */ + { 0x00000f0c, 0x0000 }, /* R3852 (0xf0c) - ANC Coefficient */ + { 0x00000f0d, 0x0000 }, /* R3853 (0xf0d) - ANC Coefficient */ + { 0x00000f0e, 0x0000 }, /* R3854 (0xf0e) - ANC Coefficient */ + { 0x00000f0f, 0x0000 }, /* R3855 (0xf0f) - ANC Coefficient */ + { 0x00000f10, 0x0000 }, /* R3856 (0xf10) - ANC Coefficient */ + { 0x00000f11, 0x0000 }, /* R3857 (0xf11) - ANC Coefficient */ + { 0x00000f12, 0x0000 }, /* R3858 (0xf12) - ANC Coefficient */ + { 0x00000f15, 0x0000 }, /* R3861 (0xf15) - FCL Filter Control */ + { 0x00000f17, 0x0004 }, /* R3863 (0xf17) - FCL ADC Reformatter Control */ + { 0x00000f18, 0x0004 }, /* R3864 (0xf18) - ANC Coefficient */ + { 0x00000f19, 0x0002 }, /* R3865 (0xf19) - ANC Coefficient */ + { 0x00000f1a, 0x0000 }, /* R3866 (0xf1a) - ANC Coefficient */ + { 0x00000f1b, 0x0010 }, /* R3867 (0xf1b) - ANC Coefficient */ + { 0x00000f1c, 0x0000 }, /* R3868 (0xf1c) - ANC Coefficient */ + { 0x00000f1d, 0x0000 }, /* R3869 (0xf1d) - ANC Coefficient */ + { 0x00000f1e, 0x0000 }, /* R3870 (0xf1e) - ANC Coefficient */ + { 0x00000f1f, 0x0000 }, /* R3871 (0xf1f) - ANC Coefficient */ + { 0x00000f20, 0x0000 }, /* R3872 (0xf20) - ANC Coefficient */ + { 0x00000f21, 0x0000 }, /* R3873 (0xf21) - ANC Coefficient */ + { 0x00000f22, 0x0000 }, /* R3874 (0xf22) - ANC Coefficient */ + { 0x00000f23, 0x0000 }, /* R3875 (0xf23) - ANC Coefficient */ + { 0x00000f24, 0x0000 }, /* R3876 (0xf24) - ANC Coefficient */ + { 0x00000f25, 0x0000 }, /* R3877 (0xf25) - ANC Coefficient */ + { 0x00000f26, 0x0000 }, /* R3878 (0xf26) - ANC Coefficient */ + { 0x00000f27, 0x0000 }, /* R3879 (0xf27) - ANC Coefficient */ + { 0x00000f28, 0x0000 }, /* R3880 (0xf28) - ANC Coefficient */ + { 0x00000f29, 0x0000 }, /* R3881 (0xf29) - ANC Coefficient */ + { 0x00000f2a, 0x0000 }, /* R3882 (0xf2a) - ANC Coefficient */ + { 0x00000f2b, 0x0000 }, /* R3883 (0xf2b) - ANC Coefficient */ + { 0x00000f2c, 0x0000 }, /* R3884 (0xf2c) - ANC Coefficient */ + { 0x00000f2d, 0x0000 }, /* R3885 (0xf2d) - ANC Coefficient */ + { 0x00000f2e, 0x0000 }, /* R3886 (0xf2e) - ANC Coefficient */ + { 0x00000f2f, 0x0000 }, /* R3887 (0xf2f) - ANC Coefficient */ + { 0x00000f30, 0x0000 }, /* R3888 (0xf30) - ANC Coefficient */ + { 0x00000f31, 0x0000 }, /* R3889 (0xf31) - ANC Coefficient */ + { 0x00000f32, 0x0000 }, /* R3890 (0xf32) - ANC Coefficient */ + { 0x00000f33, 0x0000 }, /* R3891 (0xf33) - ANC Coefficient */ + { 0x00000f34, 0x0000 }, /* R3892 (0xf34) - ANC Coefficient */ + { 0x00000f35, 0x0000 }, /* R3893 (0xf35) - ANC Coefficient */ + { 0x00000f36, 0x0000 }, /* R3894 (0xf36) - ANC Coefficient */ + { 0x00000f37, 0x0000 }, /* R3895 (0xf37) - ANC Coefficient */ + { 0x00000f38, 0x0000 }, /* R3896 (0xf38) - ANC Coefficient */ + { 0x00000f39, 0x0000 }, /* R3897 (0xf39) - ANC Coefficient */ + { 0x00000f3a, 0x0000 }, /* R3898 (0xf3a) - ANC Coefficient */ + { 0x00000f3b, 0x0000 }, /* R3899 (0xf3b) - ANC Coefficient */ + { 0x00000f3c, 0x0000 }, /* R3900 (0xf3c) - ANC Coefficient */ + { 0x00000f3d, 0x0000 }, /* R3901 (0xf3d) - ANC Coefficient */ + { 0x00000f3e, 0x0000 }, /* R3902 (0xf3e) - ANC Coefficient */ + { 0x00000f3f, 0x0000 }, /* R3903 (0xf3f) - ANC Coefficient */ + { 0x00000f40, 0x0000 }, /* R3904 (0xf40) - ANC Coefficient */ + { 0x00000f41, 0x0000 }, /* R3905 (0xf41) - ANC Coefficient */ + { 0x00000f42, 0x0000 }, /* R3906 (0xf42) - ANC Coefficient */ + { 0x00000f43, 0x0000 }, /* R3907 (0xf43) - ANC Coefficient */ + { 0x00000f44, 0x0000 }, /* R3908 (0xf44) - ANC Coefficient */ + { 0x00000f45, 0x0000 }, /* R3909 (0xf45) - ANC Coefficient */ + { 0x00000f46, 0x0000 }, /* R3910 (0xf46) - ANC Coefficient */ + { 0x00000f47, 0x0000 }, /* R3911 (0xf47) - ANC Coefficient */ + { 0x00000f48, 0x0000 }, /* R3912 (0xf48) - ANC Coefficient */ + { 0x00000f49, 0x0000 }, /* R3913 (0xf49) - ANC Coefficient */ + { 0x00000f4a, 0x0000 }, /* R3914 (0xf4a) - ANC Coefficient */ + { 0x00000f4b, 0x0000 }, /* R3915 (0xf4b) - ANC Coefficient */ + { 0x00000f4c, 0x0000 }, /* R3916 (0xf4c) - ANC Coefficient */ + { 0x00000f4d, 0x0000 }, /* R3917 (0xf4d) - ANC Coefficient */ + { 0x00000f4e, 0x0000 }, /* R3918 (0xf4e) - ANC Coefficient */ + { 0x00000f4f, 0x0000 }, /* R3919 (0xf4f) - ANC Coefficient */ + { 0x00000f50, 0x0000 }, /* R3920 (0xf50) - ANC Coefficient */ + { 0x00000f51, 0x0000 }, /* R3921 (0xf51) - ANC Coefficient */ + { 0x00000f52, 0x0000 }, /* R3922 (0xf52) - ANC Coefficient */ + { 0x00000f53, 0x0000 }, /* R3923 (0xf53) - ANC Coefficient */ + { 0x00000f54, 0x0000 }, /* R3924 (0xf54) - ANC Coefficient */ + { 0x00000f55, 0x0000 }, /* R3925 (0xf55) - ANC Coefficient */ + { 0x00000f56, 0x0000 }, /* R3926 (0xf56) - ANC Coefficient */ + { 0x00000f57, 0x0000 }, /* R3927 (0xf57) - ANC Coefficient */ + { 0x00000f58, 0x0000 }, /* R3928 (0xf58) - ANC Coefficient */ + { 0x00000f59, 0x0000 }, /* R3929 (0xf59) - ANC Coefficient */ + { 0x00000f5a, 0x0000 }, /* R3930 (0xf5a) - ANC Coefficient */ + { 0x00000f5b, 0x0000 }, /* R3931 (0xf5b) - ANC Coefficient */ + { 0x00000f5c, 0x0000 }, /* R3932 (0xf5c) - ANC Coefficient */ + { 0x00000f5d, 0x0000 }, /* R3933 (0xf5d) - ANC Coefficient */ + { 0x00000f5e, 0x0000 }, /* R3934 (0xf5e) - ANC Coefficient */ + { 0x00000f5f, 0x0000 }, /* R3935 (0xf5f) - ANC Coefficient */ + { 0x00000f60, 0x0000 }, /* R3936 (0xf60) - ANC Coefficient */ + { 0x00000f61, 0x0000 }, /* R3937 (0xf61) - ANC Coefficient */ + { 0x00000f62, 0x0000 }, /* R3938 (0xf62) - ANC Coefficient */ + { 0x00000f63, 0x0000 }, /* R3939 (0xf63) - ANC Coefficient */ + { 0x00000f64, 0x0000 }, /* R3940 (0xf64) - ANC Coefficient */ + { 0x00000f65, 0x0000 }, /* R3941 (0xf65) - ANC Coefficient */ + { 0x00000f66, 0x0000 }, /* R3942 (0xf66) - ANC Coefficient */ + { 0x00000f67, 0x0000 }, /* R3943 (0xf67) - ANC Coefficient */ + { 0x00000f68, 0x0000 }, /* R3944 (0xf68) - ANC Coefficient */ + { 0x00000f69, 0x0000 }, /* R3945 (0xf69) - ANC Coefficient */ + { 0x00000f71, 0x0000 }, /* R3953 (0xf71) - FCR Filter Control */ + { 0x00000f73, 0x0004 }, /* R3955 (0xf73) - FCR ADC Reformatter Control */ + { 0x00000f74, 0x0004 }, /* R3956 (0xf74) - ANC Coefficient */ + { 0x00000f75, 0x0002 }, /* R3957 (0xf75) - ANC Coefficient */ + { 0x00000f76, 0x0000 }, /* R3958 (0xf76) - ANC Coefficient */ + { 0x00000f77, 0x0010 }, /* R3959 (0xf77) - ANC Coefficient */ + { 0x00000f78, 0x0000 }, /* R3960 (0xf78) - ANC Coefficient */ + { 0x00000f79, 0x0000 }, /* R3961 (0xf79) - ANC Coefficient */ + { 0x00000f7a, 0x0000 }, /* R3962 (0xf7a) - ANC Coefficient */ + { 0x00000f7b, 0x0000 }, /* R3963 (0xf7b) - ANC Coefficient */ + { 0x00000f7c, 0x0000 }, /* R3964 (0xf7c) - ANC Coefficient */ + { 0x00000f7d, 0x0000 }, /* R3965 (0xf7d) - ANC Coefficient */ + { 0x00000f7e, 0x0000 }, /* R3966 (0xf7e) - ANC Coefficient */ + { 0x00000f7f, 0x0000 }, /* R3967 (0xf7f) - ANC Coefficient */ + { 0x00000f80, 0x0000 }, /* R3968 (0xf80) - ANC Coefficient */ + { 0x00000f81, 0x0000 }, /* R3969 (0xf81) - ANC Coefficient */ + { 0x00000f82, 0x0000 }, /* R3970 (0xf82) - ANC Coefficient */ + { 0x00000f83, 0x0000 }, /* R3971 (0xf83) - ANC Coefficient */ + { 0x00000f84, 0x0000 }, /* R3972 (0xf84) - ANC Coefficient */ + { 0x00000f85, 0x0000 }, /* R3973 (0xf85) - ANC Coefficient */ + { 0x00000f86, 0x0000 }, /* R3974 (0xf86) - ANC Coefficient */ + { 0x00000f87, 0x0000 }, /* R3975 (0xf87) - ANC Coefficient */ + { 0x00000f88, 0x0000 }, /* R3976 (0xf88) - ANC Coefficient */ + { 0x00000f89, 0x0000 }, /* R3977 (0xf89) - ANC Coefficient */ + { 0x00000f8a, 0x0000 }, /* R3978 (0xf8a) - ANC Coefficient */ + { 0x00000f8b, 0x0000 }, /* R3979 (0xf8b) - ANC Coefficient */ + { 0x00000f8c, 0x0000 }, /* R3980 (0xf8c) - ANC Coefficient */ + { 0x00000f8d, 0x0000 }, /* R3981 (0xf8d) - ANC Coefficient */ + { 0x00000f8e, 0x0000 }, /* R3982 (0xf8e) - ANC Coefficient */ + { 0x00000f8f, 0x0000 }, /* R3983 (0xf8f) - ANC Coefficient */ + { 0x00000f90, 0x0000 }, /* R3984 (0xf90) - ANC Coefficient */ + { 0x00000f91, 0x0000 }, /* R3985 (0xf91) - ANC Coefficient */ + { 0x00000f92, 0x0000 }, /* R3986 (0xf92) - ANC Coefficient */ + { 0x00000f93, 0x0000 }, /* R3987 (0xf93) - ANC Coefficient */ + { 0x00000f94, 0x0000 }, /* R3988 (0xf94) - ANC Coefficient */ + { 0x00000f95, 0x0000 }, /* R3989 (0xf95) - ANC Coefficient */ + { 0x00000f96, 0x0000 }, /* R3990 (0xf96) - ANC Coefficient */ + { 0x00000f97, 0x0000 }, /* R3991 (0xf97) - ANC Coefficient */ + { 0x00000f98, 0x0000 }, /* R3992 (0xf98) - ANC Coefficient */ + { 0x00000f99, 0x0000 }, /* R3993 (0xf99) - ANC Coefficient */ + { 0x00000f9a, 0x0000 }, /* R3994 (0xf9a) - ANC Coefficient */ + { 0x00000f9b, 0x0000 }, /* R3995 (0xf9b) - ANC Coefficient */ + { 0x00000f9c, 0x0000 }, /* R3996 (0xf9c) - ANC Coefficient */ + { 0x00000f9d, 0x0000 }, /* R3997 (0xf9d) - ANC Coefficient */ + { 0x00000f9e, 0x0000 }, /* R3998 (0xf9e) - ANC Coefficient */ + { 0x00000f9f, 0x0000 }, /* R3999 (0xf9f) - ANC Coefficient */ + { 0x00000fa0, 0x0000 }, /* R4000 (0xfa0) - ANC Coefficient */ + { 0x00000fa1, 0x0000 }, /* R4001 (0xfa1) - ANC Coefficient */ + { 0x00000fa2, 0x0000 }, /* R4002 (0xfa2) - ANC Coefficient */ + { 0x00000fa3, 0x0000 }, /* R4003 (0xfa3) - ANC Coefficient */ + { 0x00000fa4, 0x0000 }, /* R4004 (0xfa4) - ANC Coefficient */ + { 0x00000fa5, 0x0000 }, /* R4005 (0xfa5) - ANC Coefficient */ + { 0x00000fa6, 0x0000 }, /* R4006 (0xfa6) - ANC Coefficient */ + { 0x00000fa7, 0x0000 }, /* R4007 (0xfa7) - ANC Coefficient */ + { 0x00000fa8, 0x0000 }, /* R4008 (0xfa8) - ANC Coefficient */ + { 0x00000fa9, 0x0000 }, /* R4009 (0xfa9) - ANC Coefficient */ + { 0x00000faa, 0x0000 }, /* R4010 (0xfaa) - ANC Coefficient */ + { 0x00000fab, 0x0000 }, /* R4011 (0xfab) - ANC Coefficient */ + { 0x00000fac, 0x0000 }, /* R4012 (0xfac) - ANC Coefficient */ + { 0x00000fad, 0x0000 }, /* R4013 (0xfad) - ANC Coefficient */ + { 0x00000fae, 0x0000 }, /* R4014 (0xfae) - ANC Coefficient */ + { 0x00000faf, 0x0000 }, /* R4015 (0xfaf) - ANC Coefficient */ + { 0x00000fb0, 0x0000 }, /* R4016 (0xfb0) - ANC Coefficient */ + { 0x00000fb1, 0x0000 }, /* R4017 (0xfb1) - ANC Coefficient */ + { 0x00000fb2, 0x0000 }, /* R4018 (0xfb2) - ANC Coefficient */ + { 0x00000fb3, 0x0000 }, /* R4019 (0xfb3) - ANC Coefficient */ + { 0x00000fb4, 0x0000 }, /* R4020 (0xfb4) - ANC Coefficient */ + { 0x00000fb5, 0x0000 }, /* R4021 (0xfb5) - ANC Coefficient */ + { 0x00000fb6, 0x0000 }, /* R4022 (0xfb6) - ANC Coefficient */ + { 0x00000fb7, 0x0000 }, /* R4023 (0xfb7) - ANC Coefficient */ + { 0x00000fb8, 0x0000 }, /* R4024 (0xfb8) - ANC Coefficient */ + { 0x00000fb9, 0x0000 }, /* R4025 (0xfb9) - ANC Coefficient */ + { 0x00000fba, 0x0000 }, /* R4026 (0xfba) - ANC Coefficient */ + { 0x00000fbb, 0x0000 }, /* R4027 (0xfbb) - ANC Coefficient */ + { 0x00000fbc, 0x0000 }, /* R4028 (0xfbc) - ANC Coefficient */ + { 0x00000fbd, 0x0000 }, /* R4029 (0xfbd) - ANC Coefficient */ + { 0x00000fbe, 0x0000 }, /* R4030 (0xfbe) - ANC Coefficient */ + { 0x00000fbf, 0x0000 }, /* R4031 (0xfbf) - ANC Coefficient */ + { 0x00000fc0, 0x0000 }, /* R4032 (0xfc0) - ANC Coefficient */ + { 0x00000fc1, 0x0000 }, /* R4033 (0xfc1) - ANC Coefficient */ + { 0x00000fc2, 0x0000 }, /* R4034 (0xfc2) - ANC Coefficient */ + { 0x00000fc3, 0x0000 }, /* R4035 (0xfc3) - ANC Coefficient */ + { 0x00000fc4, 0x0000 }, /* R4036 (0xfc4) - ANC Coefficient */ + { 0x00000fc5, 0x0000 }, /* R4037 (0xfc5) - ANC Coefficient */ + { 0x00001300, 0x0000 }, /* R4864 (0x1300) - DAC Comp 1 */ + { 0x00001302, 0x0000 }, /* R4866 (0x1302) - DAC Comp 2 */ + { 0x00001380, 0x0000 }, /* R4992 (0x1380) - FRF Coefficient 1L 1 */ + { 0x00001381, 0x0000 }, /* R4993 (0x1381) - FRF Coefficient 1L 2 */ + { 0x00001382, 0x0000 }, /* R4994 (0x1382) - FRF Coefficient 1L 3 */ + { 0x00001383, 0x0000 }, /* R4995 (0x1383) - FRF Coefficient 1L 4 */ + { 0x00001390, 0x0000 }, /* R5008 (0x1390) - FRF Coefficient 1R 1 */ + { 0x00001391, 0x0000 }, /* R5009 (0x1391) - FRF Coefficient 1R 2 */ + { 0x00001392, 0x0000 }, /* R5010 (0x1392) - FRF Coefficient 1R 3 */ + { 0x00001393, 0x0000 }, /* R5011 (0x1393) - FRF Coefficient 1R 4 */ + { 0x000013a0, 0x0000 }, /* R5024 (0x13a0) - FRF Coefficient 2L 1 */ + { 0x000013a1, 0x0000 }, /* R5025 (0x13a1) - FRF Coefficient 2L 2 */ + { 0x000013a2, 0x0000 }, /* R5026 (0x13a2) - FRF Coefficient 2L 3 */ + { 0x000013a3, 0x0000 }, /* R5027 (0x13a3) - FRF Coefficient 2L 4 */ + { 0x000013b0, 0x0000 }, /* R5040 (0x13b0) - FRF Coefficient 2R 1 */ + { 0x000013b1, 0x0000 }, /* R5041 (0x13b1) - FRF Coefficient 2R 2 */ + { 0x000013b2, 0x0000 }, /* R5042 (0x13b2) - FRF Coefficient 2R 3 */ + { 0x000013b3, 0x0000 }, /* R5043 (0x13b3) - FRF Coefficient 2R 4 */ + { 0x000013c0, 0x0000 }, /* R5040 (0x13c0) - FRF Coefficient 3L 1 */ + { 0x000013c1, 0x0000 }, /* R5041 (0x13c1) - FRF Coefficient 3L 2 */ + { 0x000013c2, 0x0000 }, /* R5042 (0x13c2) - FRF Coefficient 3L 3 */ + { 0x000013c3, 0x0000 }, /* R5043 (0x13c3) - FRF Coefficient 3L 4 */ + { 0x000013d0, 0x0000 }, /* R5072 (0x13d0) - FRF Coefficient 3R 1 */ + { 0x000013d1, 0x0000 }, /* R5073 (0x13d1) - FRF Coefficient 3R 2 */ + { 0x000013d2, 0x0000 }, /* R5074 (0x13d2) - FRF Coefficient 3R 3 */ + { 0x000013d3, 0x0000 }, /* R5075 (0x13d3) - FRF Coefficient 3R 4 */ + { 0x000013e0, 0x0000 }, /* R5088 (0x13e0) - FRF Coefficient 4L 1 */ + { 0x000013e1, 0x0000 }, /* R5089 (0x13e1) - FRF Coefficient 4L 2 */ + { 0x000013e2, 0x0000 }, /* R5090 (0x13e2) - FRF Coefficient 4L 3 */ + { 0x000013e3, 0x0000 }, /* R5091 (0x13e3) - FRF Coefficient 4L 4 */ + { 0x000013f0, 0x0000 }, /* R5104 (0x13f0) - FRF Coefficient 4R 1 */ + { 0x000013f1, 0x0000 }, /* R5105 (0x13f1) - FRF Coefficient 4R 2 */ + { 0x000013f2, 0x0000 }, /* R5106 (0x13f2) - FRF Coefficient 4R 3 */ + { 0x000013f3, 0x0000 }, /* R5107 (0x13f3) - FRF Coefficient 4R 4 */ + { 0x00001400, 0x0000 }, /* R5120 (0x1400) - FRF Coefficient 5L 1 */ + { 0x00001401, 0x0000 }, /* R5121 (0x1401) - FRF Coefficient 5L 2 */ + { 0x00001402, 0x0000 }, /* R5122 (0x1402) - FRF Coefficient 5L 3 */ + { 0x00001403, 0x0000 }, /* R5123 (0x1403) - FRF Coefficient 5L 4 */ + { 0x00001410, 0x0000 }, /* R5136 (0x1410) - FRF Coefficient 5R 1 */ + { 0x00001411, 0x0000 }, /* R5137 (0x1411) - FRF Coefficient 5R 2 */ + { 0x00001412, 0x0000 }, /* R5138 (0x1412) - FRF Coefficient 5R 3 */ + { 0x00001413, 0x0000 }, /* R5139 (0x1413) - FRF Coefficient 5R 4 */ + { 0x00001420, 0x0000 }, /* R5152 (0x1420) - FRF Coefficient 6L 1 */ + { 0x00001421, 0x0000 }, /* R5153 (0x1421) - FRF Coefficient 6L 2 */ + { 0x00001422, 0x0000 }, /* R5154 (0x1422) - FRF Coefficient 6L 3 */ + { 0x00001423, 0x0000 }, /* R5155 (0x1423) - FRF Coefficient 6L 4 */ + { 0x00001430, 0x0000 }, /* R5168 (0x1430) - FRF Coefficient 6R 1 */ + { 0x00001431, 0x0000 }, /* R5169 (0x1431) - FRF Coefficient 6R 2 */ + { 0x00001432, 0x0000 }, /* R5170 (0x1432) - FRF Coefficient 6R 3 */ + { 0x00001433, 0x0000 }, /* R5171 (0x1433) - FRF Coefficient 6R 4 */ + { 0x00001700, 0x2001 }, /* R5888 (0x1700) - GPIO1 Control 1 */ + { 0x00001701, 0xe000 }, /* R5889 (0x1701) - GPIO1 Control 2 */ + { 0x00001702, 0x2001 }, /* R5890 (0x1702) - GPIO2 Control 1 */ + { 0x00001703, 0xe000 }, /* R5891 (0x1703) - GPIO2 Control 2 */ + { 0x00001704, 0x2001 }, /* R5892 (0x1704) - GPIO3 Control 1 */ + { 0x00001705, 0xe000 }, /* R5893 (0x1705) - GPIO3 Control 2 */ + { 0x00001706, 0x2001 }, /* R5894 (0x1706) - GPIO4 Control 1 */ + { 0x00001707, 0xe000 }, /* R5895 (0x1707) - GPIO4 Control 2 */ + { 0x00001708, 0x2001 }, /* R5896 (0x1708) - GPIO5 Control 1 */ + { 0x00001709, 0xe000 }, /* R5897 (0x1709) - GPIO5 Control 2 */ + { 0x0000170a, 0x2001 }, /* R5898 (0x170a) - GPIO6 Control 1 */ + { 0x0000170b, 0xe000 }, /* R5899 (0x170b) - GPIO6 Control 2 */ + { 0x0000170c, 0x2001 }, /* R5900 (0x170c) - GPIO7 Control 1 */ + { 0x0000170d, 0xe000 }, /* R5901 (0x170d) - GPIO7 Control 2 */ + { 0x0000170e, 0x2001 }, /* R5902 (0x170e) - GPIO8 Control 1 */ + { 0x0000170f, 0xe000 }, /* R5903 (0x170f) - GPIO8 Control 2 */ + { 0x00001710, 0x2001 }, /* R5904 (0x1710) - GPIO9 Control 1 */ + { 0x00001711, 0xe000 }, /* R5905 (0x1711) - GPIO9 Control 2 */ + { 0x00001712, 0x2001 }, /* R5906 (0x1712) - GPIO10 Control 1 */ + { 0x00001713, 0xe000 }, /* R5907 (0x1713) - GPIO10 Control 2 */ + { 0x00001714, 0x2001 }, /* R5908 (0x1714) - GPIO11 Control 1 */ + { 0x00001715, 0xe000 }, /* R5909 (0x1715) - GPIO11 Control 2 */ + { 0x00001716, 0x2001 }, /* R5910 (0x1716) - GPIO12 Control 1 */ + { 0x00001717, 0xe000 }, /* R5911 (0x1717) - GPIO12 Control 2 */ + { 0x00001718, 0x2001 }, /* R5912 (0x1718) - GPIO13 Control 1 */ + { 0x00001719, 0xE000 }, /* R5913 (0x1719) - GPIO13 Control 2 */ + { 0x0000171a, 0x2001 }, /* R5914 (0x171a) - GPIO14 Control 1 */ + { 0x0000171b, 0xE000 }, /* R5915 (0x171b) - GPIO14 Control 2 */ + { 0x0000171c, 0x2001 }, /* R5916 (0x171c) - GPIO15 Control 1 */ + { 0x0000171d, 0xE000 }, /* R5917 (0x171d) - GPIO15 Control 2 */ + { 0x0000171e, 0x2001 }, /* R5918 (0x171e) - GPIO16 Control 1 */ + { 0x0000171f, 0xE000 }, /* R5919 (0x171f) - GPIO16 Control 2 */ + { 0x00001720, 0x2001 }, /* R5920 (0x1720) - GPIO17 Control 1 */ + { 0x00001721, 0xe000 }, /* R5921 (0x1721) - GPIO17 Control 2 */ + { 0x00001722, 0x2001 }, /* R5922 (0x1722) - GPIO18 Control 1 */ + { 0x00001723, 0xe000 }, /* R5923 (0x1723) - GPIO18 Control 2 */ + { 0x00001724, 0x2001 }, /* R5924 (0x1724) - GPIO19 Control 1 */ + { 0x00001725, 0xe000 }, /* R5925 (0x1725) - GPIO19 Control 2 */ + { 0x00001726, 0x2001 }, /* R5926 (0x1726) - GPIO20 Control 1 */ + { 0x00001727, 0xe000 }, /* R5927 (0x1727) - GPIO20 Control 2 */ + { 0x00001728, 0x2001 }, /* R5928 (0x1728) - GPIO21 Control 1 */ + { 0x00001729, 0xe000 }, /* R5929 (0x1729) - GPIO21 Control 2 */ + { 0x0000172a, 0x2001 }, /* R5930 (0x172a) - GPIO22 Control 1 */ + { 0x0000172b, 0xe000 }, /* R5931 (0x172b) - GPIO22 Control 2 */ + { 0x0000172c, 0x2001 }, /* R5932 (0x172c) - GPIO23 Control 1 */ + { 0x0000172d, 0xe000 }, /* R5933 (0x172d) - GPIO23 Control 2 */ + { 0x0000172e, 0x2001 }, /* R5934 (0x172e) - GPIO24 Control 1 */ + { 0x0000172f, 0xe000 }, /* R5935 (0x172f) - GPIO24 Control 2 */ + { 0x00001730, 0x2001 }, /* R5936 (0x1730) - GPIO25 Control 1 */ + { 0x00001731, 0xe000 }, /* R5937 (0x1731) - GPIO25 Control 2 */ + { 0x00001732, 0x2001 }, /* R5938 (0x1732) - GPIO26 Control 1 */ + { 0x00001733, 0xe000 }, /* R5939 (0x1733) - GPIO26 Control 2 */ + { 0x00001734, 0x2001 }, /* R5940 (0x1734) - GPIO27 Control 1 */ + { 0x00001735, 0xe000 }, /* R5941 (0x1735) - GPIO27 Control 2 */ + { 0x00001736, 0x2001 }, /* R5942 (0x1736) - GPIO28 Control 1 */ + { 0x00001737, 0xe000 }, /* R5943 (0x1737) - GPIO28 Control 2 */ + { 0x00001738, 0x2001 }, /* R5944 (0x1738) - GPIO29 Control 1 */ + { 0x00001739, 0xe000 }, /* R5945 (0x1739) - GPIO29 Control 2 */ + { 0x0000173a, 0x2001 }, /* R5946 (0x173a) - GPIO30 Control 1 */ + { 0x0000173b, 0xe000 }, /* R5947 (0x173b) - GPIO30 Control 2 */ + { 0x0000173c, 0x2001 }, /* R5948 (0x173c) - GPIO31 Control 1 */ + { 0x0000173d, 0xe000 }, /* R5949 (0x173d) - GPIO31 Control 2 */ + { 0x0000173e, 0x2001 }, /* R5950 (0x173e) - GPIO32 Control 1 */ + { 0x0000173f, 0xe000 }, /* R5951 (0x173f) - GPIO32 Control 2 */ + { 0x00001740, 0x2001 }, /* R5952 (0x1740) - GPIO33 Control 1 */ + { 0x00001741, 0xe000 }, /* R5953 (0x1741) - GPIO33 Control 2 */ + { 0x00001742, 0x2001 }, /* R5954 (0x1742) - GPIO34 Control 1 */ + { 0x00001743, 0xe000 }, /* R5955 (0x1743) - GPIO34 Control 2 */ + { 0x00001744, 0x2001 }, /* R5956 (0x1744) - GPIO35 Control 1 */ + { 0x00001745, 0xe000 }, /* R5957 (0x1745) - GPIO35 Control 2 */ + { 0x00001746, 0x2001 }, /* R5958 (0x1746) - GPIO36 Control 1 */ + { 0x00001747, 0xe000 }, /* R5959 (0x1747) - GPIO36 Control 2 */ + { 0x00001748, 0x2001 }, /* R5960 (0x1748) - GPIO37 Control 1 */ + { 0x00001749, 0xe000 }, /* R5961 (0x1749) - GPIO37 Control 2 */ + { 0x0000174a, 0x2001 }, /* R5962 (0x174a) - GPIO38 Control 1 */ + { 0x0000174b, 0xe000 }, /* R5963 (0x174b) - GPIO38 Control 2 */ + { 0x0000174c, 0x2001 }, /* R5964 (0x174c) - GPIO39 Control 1 */ + { 0x0000174d, 0xe000 }, /* R5965 (0x174d) - GPIO39 Control 2 */ + { 0x0000174e, 0x2001 }, /* R5966 (0x174e) - GPIO40 Control 1 */ + { 0x0000174f, 0xe000 }, /* R5967 (0x174f) - GPIO40 Control 2 */ + { 0x00001840, 0xffff }, /* R6208 (0x1840) - IRQ1 Mask 1 */ + { 0x00001841, 0xffff }, /* R6209 (0x1841) - IRQ1 Mask 2 */ + { 0x00001842, 0xffff }, /* R6210 (0x1842) - IRQ1 Mask 3 */ + { 0x00001843, 0xffff }, /* R6211 (0x1843) - IRQ1 Mask 4 */ + { 0x00001844, 0xffff }, /* R6212 (0x1844) - IRQ1 Mask 5 */ + { 0x00001845, 0xffff }, /* R6213 (0x1845) - IRQ1 Mask 6 */ + { 0x00001846, 0xffff }, /* R6214 (0x1846) - IRQ1 Mask 7 */ + { 0x00001847, 0xffff }, /* R6215 (0x1847) - IRQ1 Mask 8 */ + { 0x00001848, 0xffff }, /* R6216 (0x1848) - IRQ1 Mask 9 */ + { 0x00001849, 0xffff }, /* R6217 (0x1849) - IRQ1 Mask 10 */ + { 0x0000184a, 0xffff }, /* R6218 (0x184a) - IRQ1 Mask 11 */ + { 0x0000184b, 0xffff }, /* R6219 (0x184b) - IRQ1 Mask 12 */ + { 0x0000184c, 0xffff }, /* R6220 (0x184c) - IRQ1 Mask 13 */ + { 0x0000184d, 0xffff }, /* R6221 (0x184d) - IRQ1 Mask 14 */ + { 0x0000184e, 0xffff }, /* R6222 (0x184e) - IRQ1 Mask 15 */ + { 0x0000184f, 0xffff }, /* R6223 (0x184f) - IRQ1 Mask 16 */ + { 0x00001850, 0xffff }, /* R6224 (0x1850) - IRQ1 Mask 17 */ + { 0x00001851, 0xffff }, /* R6225 (0x1851) - IRQ1 Mask 18 */ + { 0x00001852, 0xffff }, /* R6226 (0x1852) - IRQ1 Mask 19 */ + { 0x00001853, 0xffff }, /* R6227 (0x1853) - IRQ1 Mask 20 */ + { 0x00001854, 0xffff }, /* R6228 (0x1854) - IRQ1 Mask 21 */ + { 0x00001855, 0xffff }, /* R6229 (0x1855) - IRQ1 Mask 22 */ + { 0x00001856, 0xffff }, /* R6230 (0x1856) - IRQ1 Mask 23 */ + { 0x00001857, 0xffff }, /* R6231 (0x1857) - IRQ1 Mask 24 */ + { 0x00001858, 0xffff }, /* R6232 (0x1858) - IRQ1 Mask 25 */ + { 0x00001859, 0xffff }, /* R6233 (0x1859) - IRQ1 Mask 26 */ + { 0x0000185a, 0xffff }, /* R6234 (0x185a) - IRQ1 Mask 27 */ + { 0x0000185b, 0xffff }, /* R6235 (0x185b) - IRQ1 Mask 28 */ + { 0x0000185c, 0xffff }, /* R6236 (0x185c) - IRQ1 Mask 29 */ + { 0x0000185d, 0xffff }, /* R6237 (0x185d) - IRQ1 Mask 30 */ + { 0x0000185e, 0xffff }, /* R6238 (0x185e) - IRQ1 Mask 31 */ + { 0x0000185f, 0xffff }, /* R6239 (0x185f) - IRQ1 Mask 32 */ + { 0x00001860, 0xffff }, /* R6240 (0x1860) - IRQ1 Mask 33 */ + { 0x00001a06, 0x0000 }, /* R6662 (0x1a06) - Interrupt Debounce 7 */ + { 0x00001a80, 0x4400 }, /* R6784 (0x1a80) - IRQ1 CTRL */ +}; + +static bool cs47l85_is_adsp_memory(unsigned int reg) +{ + switch (reg) { + case 0x080000 ... 0x085ffe: + case 0x0a0000 ... 0x0a7ffe: + case 0x0c0000 ... 0x0c1ffe: + case 0x0e0000 ... 0x0e1ffe: + case 0x100000 ... 0x10effe: + case 0x120000 ... 0x12bffe: + case 0x136000 ... 0x137ffe: + case 0x140000 ... 0x14bffe: + case 0x160000 ... 0x161ffe: + case 0x180000 ... 0x18effe: + case 0x1a0000 ... 0x1b1ffe: + case 0x1b6000 ... 0x1b7ffe: + case 0x1c0000 ... 0x1cbffe: + case 0x1e0000 ... 0x1e1ffe: + case 0x200000 ... 0x208ffe: + case 0x220000 ... 0x231ffe: + case 0x240000 ... 0x24bffe: + case 0x260000 ... 0x261ffe: + case 0x280000 ... 0x288ffe: + case 0x2a0000 ... 0x2a9ffe: + case 0x2c0000 ... 0x2c3ffe: + case 0x2e0000 ... 0x2e1ffe: + case 0x300000 ... 0x305ffe: + case 0x320000 ... 0x333ffe: + case 0x340000 ... 0x34bffe: + case 0x360000 ... 0x361ffe: + case 0x380000 ... 0x388ffe: + case 0x3a0000 ... 0x3a7ffe: + case 0x3c0000 ... 0x3c1ffe: + case 0x3e0000 ... 0x3e1ffe: + return true; + default: + return false; + } +} + +static bool cs47l85_16bit_readable_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_SOFTWARE_RESET: + case MADERA_HARDWARE_REVISION: + case MADERA_WRITE_SEQUENCER_CTRL_0: + case MADERA_WRITE_SEQUENCER_CTRL_1: + case MADERA_WRITE_SEQUENCER_CTRL_2: + case MADERA_TONE_GENERATOR_1: + case MADERA_TONE_GENERATOR_2: + case MADERA_TONE_GENERATOR_3: + case MADERA_TONE_GENERATOR_4: + case MADERA_TONE_GENERATOR_5: + case MADERA_PWM_DRIVE_1: + case MADERA_PWM_DRIVE_2: + case MADERA_PWM_DRIVE_3: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_1: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_2: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_3: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_4: + case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1: + case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: + case MADERA_HAPTICS_CONTROL_1: + case MADERA_HAPTICS_CONTROL_2: + case MADERA_HAPTICS_PHASE_1_INTENSITY: + case MADERA_HAPTICS_PHASE_1_DURATION: + case MADERA_HAPTICS_PHASE_2_INTENSITY: + case MADERA_HAPTICS_PHASE_2_DURATION: + case MADERA_HAPTICS_PHASE_3_INTENSITY: + case MADERA_HAPTICS_PHASE_3_DURATION: + case MADERA_HAPTICS_STATUS: + case MADERA_COMFORT_NOISE_GENERATOR: + case MADERA_CLOCK_32K_1: + case MADERA_SYSTEM_CLOCK_1: + case MADERA_SAMPLE_RATE_1: + case MADERA_SAMPLE_RATE_2: + case MADERA_SAMPLE_RATE_3: + case MADERA_SAMPLE_RATE_1_STATUS: + case MADERA_SAMPLE_RATE_2_STATUS: + case MADERA_SAMPLE_RATE_3_STATUS: + case MADERA_ASYNC_CLOCK_1: + case MADERA_ASYNC_SAMPLE_RATE_1: + case MADERA_ASYNC_SAMPLE_RATE_1_STATUS: + case MADERA_ASYNC_SAMPLE_RATE_2: + case MADERA_ASYNC_SAMPLE_RATE_2_STATUS: + case MADERA_DSP_CLOCK_1: + case MADERA_DSP_CLOCK_2: + case MADERA_OUTPUT_SYSTEM_CLOCK: + case MADERA_OUTPUT_ASYNC_CLOCK: + case MADERA_RATE_ESTIMATOR_1: + case MADERA_RATE_ESTIMATOR_2: + case MADERA_RATE_ESTIMATOR_3: + case MADERA_RATE_ESTIMATOR_4: + case MADERA_RATE_ESTIMATOR_5: + case MADERA_FLL1_CONTROL_1: + case MADERA_FLL1_CONTROL_2: + case MADERA_FLL1_CONTROL_3: + case MADERA_FLL1_CONTROL_4: + case MADERA_FLL1_CONTROL_5: + case MADERA_FLL1_CONTROL_6: + case MADERA_FLL1_CONTROL_7: + case MADERA_FLL1_LOOP_FILTER_TEST_1: + case MADERA_FLL1_SYNCHRONISER_1: + case MADERA_FLL1_SYNCHRONISER_2: + case MADERA_FLL1_SYNCHRONISER_3: + case MADERA_FLL1_SYNCHRONISER_4: + case MADERA_FLL1_SYNCHRONISER_5: + case MADERA_FLL1_SYNCHRONISER_6: + case MADERA_FLL1_SYNCHRONISER_7: + case MADERA_FLL1_SPREAD_SPECTRUM: + case MADERA_FLL1_GPIO_CLOCK: + case MADERA_FLL2_CONTROL_1: + case MADERA_FLL2_CONTROL_2: + case MADERA_FLL2_CONTROL_3: + case MADERA_FLL2_CONTROL_4: + case MADERA_FLL2_CONTROL_5: + case MADERA_FLL2_CONTROL_6: + case MADERA_FLL2_CONTROL_7: + case MADERA_FLL2_LOOP_FILTER_TEST_1: + case MADERA_FLL2_SYNCHRONISER_1: + case MADERA_FLL2_SYNCHRONISER_2: + case MADERA_FLL2_SYNCHRONISER_3: + case MADERA_FLL2_SYNCHRONISER_4: + case MADERA_FLL2_SYNCHRONISER_5: + case MADERA_FLL2_SYNCHRONISER_6: + case MADERA_FLL2_SYNCHRONISER_7: + case MADERA_FLL2_SPREAD_SPECTRUM: + case MADERA_FLL2_GPIO_CLOCK: + case MADERA_FLL3_CONTROL_1: + case MADERA_FLL3_CONTROL_2: + case MADERA_FLL3_CONTROL_3: + case MADERA_FLL3_CONTROL_4: + case MADERA_FLL3_CONTROL_5: + case MADERA_FLL3_CONTROL_6: + case MADERA_FLL3_CONTROL_7: + case MADERA_FLL3_LOOP_FILTER_TEST_1: + case MADERA_FLL3_SYNCHRONISER_1: + case MADERA_FLL3_SYNCHRONISER_2: + case MADERA_FLL3_SYNCHRONISER_3: + case MADERA_FLL3_SYNCHRONISER_4: + case MADERA_FLL3_SYNCHRONISER_5: + case MADERA_FLL3_SYNCHRONISER_6: + case MADERA_FLL3_SYNCHRONISER_7: + case MADERA_FLL3_SPREAD_SPECTRUM: + case MADERA_FLL3_GPIO_CLOCK: + case MADERA_MIC_CHARGE_PUMP_1: + case MADERA_HP_CHARGE_PUMP_8: + case MADERA_LDO1_CONTROL_1: + case MADERA_LDO2_CONTROL_1: + case MADERA_MIC_BIAS_CTRL_1: + case MADERA_MIC_BIAS_CTRL_2: + case MADERA_MIC_BIAS_CTRL_3: + case MADERA_MIC_BIAS_CTRL_4: + case MADERA_HP_CTRL_1L: + case MADERA_HP_CTRL_1R: + case MADERA_HP_CTRL_2L: + case MADERA_HP_CTRL_2R: + case MADERA_HP_CTRL_3L: + case MADERA_HP_CTRL_3R: + case MADERA_DCS_HP1L_CONTROL: + case MADERA_DCS_HP1R_CONTROL: + case MADERA_EDRE_HP_STEREO_CONTROL: + case MADERA_ACCESSORY_DETECT_MODE_1: + case MADERA_HEADPHONE_DETECT_1: + case MADERA_HEADPHONE_DETECT_2: + case MADERA_HEADPHONE_DETECT_3: + case MADERA_HEADPHONE_DETECT_5: + case MADERA_MICD_CLAMP_CONTROL: + case MADERA_MIC_DETECT_1_CONTROL_1: + case MADERA_MIC_DETECT_1_CONTROL_2: + case MADERA_MIC_DETECT_1_CONTROL_3: + case MADERA_MIC_DETECT_1_LEVEL_1: + case MADERA_MIC_DETECT_1_LEVEL_2: + case MADERA_MIC_DETECT_1_LEVEL_3: + case MADERA_MIC_DETECT_1_LEVEL_4: + case MADERA_MIC_DETECT_1_CONTROL_4: + case MADERA_GP_SWITCH_1: + case MADERA_JACK_DETECT_ANALOGUE: + case MADERA_INPUT_ENABLES: + case MADERA_INPUT_ENABLES_STATUS: + case MADERA_INPUT_RATE: + case MADERA_INPUT_VOLUME_RAMP: + case MADERA_HPF_CONTROL: + case MADERA_IN1L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_1L: + case MADERA_DMIC1L_CONTROL: + case MADERA_IN1R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_1R: + case MADERA_DMIC1R_CONTROL: + case MADERA_IN2L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_2L: + case MADERA_DMIC2L_CONTROL: + case MADERA_IN2R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_2R: + case MADERA_DMIC2R_CONTROL: + case MADERA_IN3L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_3L: + case MADERA_DMIC3L_CONTROL: + case MADERA_IN3R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_3R: + case MADERA_DMIC3R_CONTROL: + case MADERA_IN4L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_4L: + case MADERA_DMIC4L_CONTROL: + case MADERA_IN4R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_4R: + case MADERA_DMIC4R_CONTROL: + case MADERA_IN5L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_5L: + case MADERA_DMIC5L_CONTROL: + case MADERA_IN5R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_5R: + case MADERA_DMIC5R_CONTROL: + case MADERA_IN6L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_6L: + case MADERA_DMIC6L_CONTROL: + case MADERA_IN6R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_6R: + case MADERA_DMIC6R_CONTROL: + case MADERA_OUTPUT_ENABLES_1: + case MADERA_OUTPUT_STATUS_1: + case MADERA_RAW_OUTPUT_STATUS_1: + case MADERA_OUTPUT_RATE_1: + case MADERA_OUTPUT_VOLUME_RAMP: + case MADERA_OUTPUT_PATH_CONFIG_1L: + case MADERA_DAC_DIGITAL_VOLUME_1L: + case MADERA_NOISE_GATE_SELECT_1L: + case MADERA_OUTPUT_PATH_CONFIG_1R: + case MADERA_DAC_DIGITAL_VOLUME_1R: + case MADERA_NOISE_GATE_SELECT_1R: + case MADERA_OUTPUT_PATH_CONFIG_2L: + case MADERA_DAC_DIGITAL_VOLUME_2L: + case MADERA_NOISE_GATE_SELECT_2L: + case MADERA_OUTPUT_PATH_CONFIG_2R: + case MADERA_DAC_DIGITAL_VOLUME_2R: + case MADERA_NOISE_GATE_SELECT_2R: + case MADERA_OUTPUT_PATH_CONFIG_3L: + case MADERA_DAC_DIGITAL_VOLUME_3L: + case MADERA_NOISE_GATE_SELECT_3L: + case MADERA_OUTPUT_PATH_CONFIG_3R: + case MADERA_DAC_DIGITAL_VOLUME_3R: + case MADERA_NOISE_GATE_SELECT_3R: + case MADERA_OUTPUT_PATH_CONFIG_4L: + case MADERA_DAC_DIGITAL_VOLUME_4L: + case MADERA_NOISE_GATE_SELECT_4L: + case MADERA_OUTPUT_PATH_CONFIG_4R: + case MADERA_DAC_DIGITAL_VOLUME_4R: + case MADERA_NOISE_GATE_SELECT_4R: + case MADERA_OUTPUT_PATH_CONFIG_5L: + case MADERA_DAC_DIGITAL_VOLUME_5L: + case MADERA_NOISE_GATE_SELECT_5L: + case MADERA_OUTPUT_PATH_CONFIG_5R: + case MADERA_DAC_DIGITAL_VOLUME_5R: + case MADERA_NOISE_GATE_SELECT_5R: + case MADERA_OUTPUT_PATH_CONFIG_6L: + case MADERA_DAC_DIGITAL_VOLUME_6L: + case MADERA_NOISE_GATE_SELECT_6L: + case MADERA_OUTPUT_PATH_CONFIG_6R: + case MADERA_DAC_DIGITAL_VOLUME_6R: + case MADERA_NOISE_GATE_SELECT_6R: + case MADERA_DRE_ENABLE: + case MADERA_EDRE_ENABLE: + case MADERA_EDRE_MANUAL: + case MADERA_DAC_AEC_CONTROL_1: + case MADERA_DAC_AEC_CONTROL_2: + case MADERA_NOISE_GATE_CONTROL: + case MADERA_PDM_SPK1_CTRL_1: + case MADERA_PDM_SPK1_CTRL_2: + case MADERA_PDM_SPK2_CTRL_1: + case MADERA_PDM_SPK2_CTRL_2: + case MADERA_HP1_SHORT_CIRCUIT_CTRL: + case MADERA_HP2_SHORT_CIRCUIT_CTRL: + case MADERA_HP3_SHORT_CIRCUIT_CTRL: + case MADERA_HP_TEST_CTRL_5: + case MADERA_HP_TEST_CTRL_6: + case MADERA_AIF1_BCLK_CTRL: + case MADERA_AIF1_TX_PIN_CTRL: + case MADERA_AIF1_RX_PIN_CTRL: + case MADERA_AIF1_RATE_CTRL: + case MADERA_AIF1_FORMAT: + case MADERA_AIF1_RX_BCLK_RATE: + case MADERA_AIF1_FRAME_CTRL_1: + case MADERA_AIF1_FRAME_CTRL_2: + case MADERA_AIF1_FRAME_CTRL_3: + case MADERA_AIF1_FRAME_CTRL_4: + case MADERA_AIF1_FRAME_CTRL_5: + case MADERA_AIF1_FRAME_CTRL_6: + case MADERA_AIF1_FRAME_CTRL_7: + case MADERA_AIF1_FRAME_CTRL_8: + case MADERA_AIF1_FRAME_CTRL_9: + case MADERA_AIF1_FRAME_CTRL_10: + case MADERA_AIF1_FRAME_CTRL_11: + case MADERA_AIF1_FRAME_CTRL_12: + case MADERA_AIF1_FRAME_CTRL_13: + case MADERA_AIF1_FRAME_CTRL_14: + case MADERA_AIF1_FRAME_CTRL_15: + case MADERA_AIF1_FRAME_CTRL_16: + case MADERA_AIF1_FRAME_CTRL_17: + case MADERA_AIF1_FRAME_CTRL_18: + case MADERA_AIF1_TX_ENABLES: + case MADERA_AIF1_RX_ENABLES: + case MADERA_AIF2_BCLK_CTRL: + case MADERA_AIF2_TX_PIN_CTRL: + case MADERA_AIF2_RX_PIN_CTRL: + case MADERA_AIF2_RATE_CTRL: + case MADERA_AIF2_FORMAT: + case MADERA_AIF2_RX_BCLK_RATE: + case MADERA_AIF2_FRAME_CTRL_1: + case MADERA_AIF2_FRAME_CTRL_2: + case MADERA_AIF2_FRAME_CTRL_3: + case MADERA_AIF2_FRAME_CTRL_4: + case MADERA_AIF2_FRAME_CTRL_5: + case MADERA_AIF2_FRAME_CTRL_6: + case MADERA_AIF2_FRAME_CTRL_7: + case MADERA_AIF2_FRAME_CTRL_8: + case MADERA_AIF2_FRAME_CTRL_9: + case MADERA_AIF2_FRAME_CTRL_10: + case MADERA_AIF2_FRAME_CTRL_11: + case MADERA_AIF2_FRAME_CTRL_12: + case MADERA_AIF2_FRAME_CTRL_13: + case MADERA_AIF2_FRAME_CTRL_14: + case MADERA_AIF2_FRAME_CTRL_15: + case MADERA_AIF2_FRAME_CTRL_16: + case MADERA_AIF2_FRAME_CTRL_17: + case MADERA_AIF2_FRAME_CTRL_18: + case MADERA_AIF2_TX_ENABLES: + case MADERA_AIF2_RX_ENABLES: + case MADERA_AIF3_BCLK_CTRL: + case MADERA_AIF3_TX_PIN_CTRL: + case MADERA_AIF3_RX_PIN_CTRL: + case MADERA_AIF3_RATE_CTRL: + case MADERA_AIF3_FORMAT: + case MADERA_AIF3_RX_BCLK_RATE: + case MADERA_AIF3_FRAME_CTRL_1: + case MADERA_AIF3_FRAME_CTRL_2: + case MADERA_AIF3_FRAME_CTRL_3: + case MADERA_AIF3_FRAME_CTRL_4: + case MADERA_AIF3_FRAME_CTRL_11: + case MADERA_AIF3_FRAME_CTRL_12: + case MADERA_AIF3_TX_ENABLES: + case MADERA_AIF3_RX_ENABLES: + case MADERA_AIF4_BCLK_CTRL: + case MADERA_AIF4_TX_PIN_CTRL: + case MADERA_AIF4_RX_PIN_CTRL: + case MADERA_AIF4_RATE_CTRL: + case MADERA_AIF4_FORMAT: + case MADERA_AIF4_RX_BCLK_RATE: + case MADERA_AIF4_FRAME_CTRL_1: + case MADERA_AIF4_FRAME_CTRL_2: + case MADERA_AIF4_FRAME_CTRL_3: + case MADERA_AIF4_FRAME_CTRL_4: + case MADERA_AIF4_FRAME_CTRL_11: + case MADERA_AIF4_FRAME_CTRL_12: + case MADERA_AIF4_TX_ENABLES: + case MADERA_AIF4_RX_ENABLES: + case MADERA_SPD1_TX_CONTROL: + case MADERA_SPD1_TX_CHANNEL_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_2: + case MADERA_SPD1_TX_CHANNEL_STATUS_3: + case MADERA_SLIMBUS_FRAMER_REF_GEAR: + case MADERA_SLIMBUS_RATES_1: + case MADERA_SLIMBUS_RATES_2: + case MADERA_SLIMBUS_RATES_3: + case MADERA_SLIMBUS_RATES_4: + case MADERA_SLIMBUS_RATES_5: + case MADERA_SLIMBUS_RATES_6: + case MADERA_SLIMBUS_RATES_7: + case MADERA_SLIMBUS_RATES_8: + case MADERA_SLIMBUS_RX_CHANNEL_ENABLE: + case MADERA_SLIMBUS_TX_CHANNEL_ENABLE: + case MADERA_SLIMBUS_RX_PORT_STATUS: + case MADERA_SLIMBUS_TX_PORT_STATUS: + case MADERA_PWM1MIX_INPUT_1_SOURCE: + case MADERA_PWM1MIX_INPUT_1_VOLUME: + case MADERA_PWM1MIX_INPUT_2_SOURCE: + case MADERA_PWM1MIX_INPUT_2_VOLUME: + case MADERA_PWM1MIX_INPUT_3_SOURCE: + case MADERA_PWM1MIX_INPUT_3_VOLUME: + case MADERA_PWM1MIX_INPUT_4_SOURCE: + case MADERA_PWM1MIX_INPUT_4_VOLUME: + case MADERA_PWM2MIX_INPUT_1_SOURCE: + case MADERA_PWM2MIX_INPUT_1_VOLUME: + case MADERA_PWM2MIX_INPUT_2_SOURCE: + case MADERA_PWM2MIX_INPUT_2_VOLUME: + case MADERA_PWM2MIX_INPUT_3_SOURCE: + case MADERA_PWM2MIX_INPUT_3_VOLUME: + case MADERA_PWM2MIX_INPUT_4_SOURCE: + case MADERA_PWM2MIX_INPUT_4_VOLUME: + case MADERA_OUT1LMIX_INPUT_1_SOURCE: + case MADERA_OUT1LMIX_INPUT_1_VOLUME: + case MADERA_OUT1LMIX_INPUT_2_SOURCE: + case MADERA_OUT1LMIX_INPUT_2_VOLUME: + case MADERA_OUT1LMIX_INPUT_3_SOURCE: + case MADERA_OUT1LMIX_INPUT_3_VOLUME: + case MADERA_OUT1LMIX_INPUT_4_SOURCE: + case MADERA_OUT1LMIX_INPUT_4_VOLUME: + case MADERA_OUT1RMIX_INPUT_1_SOURCE: + case MADERA_OUT1RMIX_INPUT_1_VOLUME: + case MADERA_OUT1RMIX_INPUT_2_SOURCE: + case MADERA_OUT1RMIX_INPUT_2_VOLUME: + case MADERA_OUT1RMIX_INPUT_3_SOURCE: + case MADERA_OUT1RMIX_INPUT_3_VOLUME: + case MADERA_OUT1RMIX_INPUT_4_SOURCE: + case MADERA_OUT1RMIX_INPUT_4_VOLUME: + case MADERA_OUT2LMIX_INPUT_1_SOURCE: + case MADERA_OUT2LMIX_INPUT_1_VOLUME: + case MADERA_OUT2LMIX_INPUT_2_SOURCE: + case MADERA_OUT2LMIX_INPUT_2_VOLUME: + case MADERA_OUT2LMIX_INPUT_3_SOURCE: + case MADERA_OUT2LMIX_INPUT_3_VOLUME: + case MADERA_OUT2LMIX_INPUT_4_SOURCE: + case MADERA_OUT2LMIX_INPUT_4_VOLUME: + case MADERA_OUT2RMIX_INPUT_1_SOURCE: + case MADERA_OUT2RMIX_INPUT_1_VOLUME: + case MADERA_OUT2RMIX_INPUT_2_SOURCE: + case MADERA_OUT2RMIX_INPUT_2_VOLUME: + case MADERA_OUT2RMIX_INPUT_3_SOURCE: + case MADERA_OUT2RMIX_INPUT_3_VOLUME: + case MADERA_OUT2RMIX_INPUT_4_SOURCE: + case MADERA_OUT2RMIX_INPUT_4_VOLUME: + case MADERA_OUT3LMIX_INPUT_1_SOURCE: + case MADERA_OUT3LMIX_INPUT_1_VOLUME: + case MADERA_OUT3LMIX_INPUT_2_SOURCE: + case MADERA_OUT3LMIX_INPUT_2_VOLUME: + case MADERA_OUT3LMIX_INPUT_3_SOURCE: + case MADERA_OUT3LMIX_INPUT_3_VOLUME: + case MADERA_OUT3LMIX_INPUT_4_SOURCE: + case MADERA_OUT3LMIX_INPUT_4_VOLUME: + case MADERA_OUT3RMIX_INPUT_1_SOURCE: + case MADERA_OUT3RMIX_INPUT_1_VOLUME: + case MADERA_OUT3RMIX_INPUT_2_SOURCE: + case MADERA_OUT3RMIX_INPUT_2_VOLUME: + case MADERA_OUT3RMIX_INPUT_3_SOURCE: + case MADERA_OUT3RMIX_INPUT_3_VOLUME: + case MADERA_OUT3RMIX_INPUT_4_SOURCE: + case MADERA_OUT3RMIX_INPUT_4_VOLUME: + case MADERA_OUT4LMIX_INPUT_1_SOURCE: + case MADERA_OUT4LMIX_INPUT_1_VOLUME: + case MADERA_OUT4LMIX_INPUT_2_SOURCE: + case MADERA_OUT4LMIX_INPUT_2_VOLUME: + case MADERA_OUT4LMIX_INPUT_3_SOURCE: + case MADERA_OUT4LMIX_INPUT_3_VOLUME: + case MADERA_OUT4LMIX_INPUT_4_SOURCE: + case MADERA_OUT4LMIX_INPUT_4_VOLUME: + case MADERA_OUT4RMIX_INPUT_1_SOURCE: + case MADERA_OUT4RMIX_INPUT_1_VOLUME: + case MADERA_OUT4RMIX_INPUT_2_SOURCE: + case MADERA_OUT4RMIX_INPUT_2_VOLUME: + case MADERA_OUT4RMIX_INPUT_3_SOURCE: + case MADERA_OUT4RMIX_INPUT_3_VOLUME: + case MADERA_OUT4RMIX_INPUT_4_SOURCE: + case MADERA_OUT4RMIX_INPUT_4_VOLUME: + case MADERA_OUT5LMIX_INPUT_1_SOURCE: + case MADERA_OUT5LMIX_INPUT_1_VOLUME: + case MADERA_OUT5LMIX_INPUT_2_SOURCE: + case MADERA_OUT5LMIX_INPUT_2_VOLUME: + case MADERA_OUT5LMIX_INPUT_3_SOURCE: + case MADERA_OUT5LMIX_INPUT_3_VOLUME: + case MADERA_OUT5LMIX_INPUT_4_SOURCE: + case MADERA_OUT5LMIX_INPUT_4_VOLUME: + case MADERA_OUT5RMIX_INPUT_1_SOURCE: + case MADERA_OUT5RMIX_INPUT_1_VOLUME: + case MADERA_OUT5RMIX_INPUT_2_SOURCE: + case MADERA_OUT5RMIX_INPUT_2_VOLUME: + case MADERA_OUT5RMIX_INPUT_3_SOURCE: + case MADERA_OUT5RMIX_INPUT_3_VOLUME: + case MADERA_OUT5RMIX_INPUT_4_SOURCE: + case MADERA_OUT5RMIX_INPUT_4_VOLUME: + case MADERA_OUT6LMIX_INPUT_1_SOURCE: + case MADERA_OUT6LMIX_INPUT_1_VOLUME: + case MADERA_OUT6LMIX_INPUT_2_SOURCE: + case MADERA_OUT6LMIX_INPUT_2_VOLUME: + case MADERA_OUT6LMIX_INPUT_3_SOURCE: + case MADERA_OUT6LMIX_INPUT_3_VOLUME: + case MADERA_OUT6LMIX_INPUT_4_SOURCE: + case MADERA_OUT6LMIX_INPUT_4_VOLUME: + case MADERA_OUT6RMIX_INPUT_1_SOURCE: + case MADERA_OUT6RMIX_INPUT_1_VOLUME: + case MADERA_OUT6RMIX_INPUT_2_SOURCE: + case MADERA_OUT6RMIX_INPUT_2_VOLUME: + case MADERA_OUT6RMIX_INPUT_3_SOURCE: + case MADERA_OUT6RMIX_INPUT_3_VOLUME: + case MADERA_OUT6RMIX_INPUT_4_SOURCE: + case MADERA_OUT6RMIX_INPUT_4_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_4_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_4_VOLUME: + case MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE: + case MADERA_SPDIF1TX1MIX_INPUT_1_VOLUME: + case MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE: + case MADERA_SPDIF1TX2MIX_INPUT_1_VOLUME: + case MADERA_EQ1MIX_INPUT_1_SOURCE: + case MADERA_EQ1MIX_INPUT_1_VOLUME: + case MADERA_EQ1MIX_INPUT_2_SOURCE: + case MADERA_EQ1MIX_INPUT_2_VOLUME: + case MADERA_EQ1MIX_INPUT_3_SOURCE: + case MADERA_EQ1MIX_INPUT_3_VOLUME: + case MADERA_EQ1MIX_INPUT_4_SOURCE: + case MADERA_EQ1MIX_INPUT_4_VOLUME: + case MADERA_EQ2MIX_INPUT_1_SOURCE: + case MADERA_EQ2MIX_INPUT_1_VOLUME: + case MADERA_EQ2MIX_INPUT_2_SOURCE: + case MADERA_EQ2MIX_INPUT_2_VOLUME: + case MADERA_EQ2MIX_INPUT_3_SOURCE: + case MADERA_EQ2MIX_INPUT_3_VOLUME: + case MADERA_EQ2MIX_INPUT_4_SOURCE: + case MADERA_EQ2MIX_INPUT_4_VOLUME: + case MADERA_EQ3MIX_INPUT_1_SOURCE: + case MADERA_EQ3MIX_INPUT_1_VOLUME: + case MADERA_EQ3MIX_INPUT_2_SOURCE: + case MADERA_EQ3MIX_INPUT_2_VOLUME: + case MADERA_EQ3MIX_INPUT_3_SOURCE: + case MADERA_EQ3MIX_INPUT_3_VOLUME: + case MADERA_EQ3MIX_INPUT_4_SOURCE: + case MADERA_EQ3MIX_INPUT_4_VOLUME: + case MADERA_EQ4MIX_INPUT_1_SOURCE: + case MADERA_EQ4MIX_INPUT_1_VOLUME: + case MADERA_EQ4MIX_INPUT_2_SOURCE: + case MADERA_EQ4MIX_INPUT_2_VOLUME: + case MADERA_EQ4MIX_INPUT_3_SOURCE: + case MADERA_EQ4MIX_INPUT_3_VOLUME: + case MADERA_EQ4MIX_INPUT_4_SOURCE: + case MADERA_EQ4MIX_INPUT_4_VOLUME: + case MADERA_DRC1LMIX_INPUT_1_SOURCE: + case MADERA_DRC1LMIX_INPUT_1_VOLUME: + case MADERA_DRC1LMIX_INPUT_2_SOURCE: + case MADERA_DRC1LMIX_INPUT_2_VOLUME: + case MADERA_DRC1LMIX_INPUT_3_SOURCE: + case MADERA_DRC1LMIX_INPUT_3_VOLUME: + case MADERA_DRC1LMIX_INPUT_4_SOURCE: + case MADERA_DRC1LMIX_INPUT_4_VOLUME: + case MADERA_DRC1RMIX_INPUT_1_SOURCE: + case MADERA_DRC1RMIX_INPUT_1_VOLUME: + case MADERA_DRC1RMIX_INPUT_2_SOURCE: + case MADERA_DRC1RMIX_INPUT_2_VOLUME: + case MADERA_DRC1RMIX_INPUT_3_SOURCE: + case MADERA_DRC1RMIX_INPUT_3_VOLUME: + case MADERA_DRC1RMIX_INPUT_4_SOURCE: + case MADERA_DRC1RMIX_INPUT_4_VOLUME: + case MADERA_DRC2LMIX_INPUT_1_SOURCE: + case MADERA_DRC2LMIX_INPUT_1_VOLUME: + case MADERA_DRC2LMIX_INPUT_2_SOURCE: + case MADERA_DRC2LMIX_INPUT_2_VOLUME: + case MADERA_DRC2LMIX_INPUT_3_SOURCE: + case MADERA_DRC2LMIX_INPUT_3_VOLUME: + case MADERA_DRC2LMIX_INPUT_4_SOURCE: + case MADERA_DRC2LMIX_INPUT_4_VOLUME: + case MADERA_DRC2RMIX_INPUT_1_SOURCE: + case MADERA_DRC2RMIX_INPUT_1_VOLUME: + case MADERA_DRC2RMIX_INPUT_2_SOURCE: + case MADERA_DRC2RMIX_INPUT_2_VOLUME: + case MADERA_DRC2RMIX_INPUT_3_SOURCE: + case MADERA_DRC2RMIX_INPUT_3_VOLUME: + case MADERA_DRC2RMIX_INPUT_4_SOURCE: + case MADERA_DRC2RMIX_INPUT_4_VOLUME: + case MADERA_HPLP1MIX_INPUT_1_SOURCE: + case MADERA_HPLP1MIX_INPUT_1_VOLUME: + case MADERA_HPLP1MIX_INPUT_2_SOURCE: + case MADERA_HPLP1MIX_INPUT_2_VOLUME: + case MADERA_HPLP1MIX_INPUT_3_SOURCE: + case MADERA_HPLP1MIX_INPUT_3_VOLUME: + case MADERA_HPLP1MIX_INPUT_4_SOURCE: + case MADERA_HPLP1MIX_INPUT_4_VOLUME: + case MADERA_HPLP2MIX_INPUT_1_SOURCE: + case MADERA_HPLP2MIX_INPUT_1_VOLUME: + case MADERA_HPLP2MIX_INPUT_2_SOURCE: + case MADERA_HPLP2MIX_INPUT_2_VOLUME: + case MADERA_HPLP2MIX_INPUT_3_SOURCE: + case MADERA_HPLP2MIX_INPUT_3_VOLUME: + case MADERA_HPLP2MIX_INPUT_4_SOURCE: + case MADERA_HPLP2MIX_INPUT_4_VOLUME: + case MADERA_HPLP3MIX_INPUT_1_SOURCE: + case MADERA_HPLP3MIX_INPUT_1_VOLUME: + case MADERA_HPLP3MIX_INPUT_2_SOURCE: + case MADERA_HPLP3MIX_INPUT_2_VOLUME: + case MADERA_HPLP3MIX_INPUT_3_SOURCE: + case MADERA_HPLP3MIX_INPUT_3_VOLUME: + case MADERA_HPLP3MIX_INPUT_4_SOURCE: + case MADERA_HPLP3MIX_INPUT_4_VOLUME: + case MADERA_HPLP4MIX_INPUT_1_SOURCE: + case MADERA_HPLP4MIX_INPUT_1_VOLUME: + case MADERA_HPLP4MIX_INPUT_2_SOURCE: + case MADERA_HPLP4MIX_INPUT_2_VOLUME: + case MADERA_HPLP4MIX_INPUT_3_SOURCE: + case MADERA_HPLP4MIX_INPUT_3_VOLUME: + case MADERA_HPLP4MIX_INPUT_4_SOURCE: + case MADERA_HPLP4MIX_INPUT_4_VOLUME: + case MADERA_DSP1LMIX_INPUT_1_SOURCE: + case MADERA_DSP1LMIX_INPUT_1_VOLUME: + case MADERA_DSP1LMIX_INPUT_2_SOURCE: + case MADERA_DSP1LMIX_INPUT_2_VOLUME: + case MADERA_DSP1LMIX_INPUT_3_SOURCE: + case MADERA_DSP1LMIX_INPUT_3_VOLUME: + case MADERA_DSP1LMIX_INPUT_4_SOURCE: + case MADERA_DSP1LMIX_INPUT_4_VOLUME: + case MADERA_DSP1RMIX_INPUT_1_SOURCE: + case MADERA_DSP1RMIX_INPUT_1_VOLUME: + case MADERA_DSP1RMIX_INPUT_2_SOURCE: + case MADERA_DSP1RMIX_INPUT_2_VOLUME: + case MADERA_DSP1RMIX_INPUT_3_SOURCE: + case MADERA_DSP1RMIX_INPUT_3_VOLUME: + case MADERA_DSP1RMIX_INPUT_4_SOURCE: + case MADERA_DSP1RMIX_INPUT_4_VOLUME: + case MADERA_DSP1AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP2LMIX_INPUT_1_SOURCE: + case MADERA_DSP2LMIX_INPUT_1_VOLUME: + case MADERA_DSP2LMIX_INPUT_2_SOURCE: + case MADERA_DSP2LMIX_INPUT_2_VOLUME: + case MADERA_DSP2LMIX_INPUT_3_SOURCE: + case MADERA_DSP2LMIX_INPUT_3_VOLUME: + case MADERA_DSP2LMIX_INPUT_4_SOURCE: + case MADERA_DSP2LMIX_INPUT_4_VOLUME: + case MADERA_DSP2RMIX_INPUT_1_SOURCE: + case MADERA_DSP2RMIX_INPUT_1_VOLUME: + case MADERA_DSP2RMIX_INPUT_2_SOURCE: + case MADERA_DSP2RMIX_INPUT_2_VOLUME: + case MADERA_DSP2RMIX_INPUT_3_SOURCE: + case MADERA_DSP2RMIX_INPUT_3_VOLUME: + case MADERA_DSP2RMIX_INPUT_4_SOURCE: + case MADERA_DSP2RMIX_INPUT_4_VOLUME: + case MADERA_DSP2AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP3LMIX_INPUT_1_SOURCE: + case MADERA_DSP3LMIX_INPUT_1_VOLUME: + case MADERA_DSP3LMIX_INPUT_2_SOURCE: + case MADERA_DSP3LMIX_INPUT_2_VOLUME: + case MADERA_DSP3LMIX_INPUT_3_SOURCE: + case MADERA_DSP3LMIX_INPUT_3_VOLUME: + case MADERA_DSP3LMIX_INPUT_4_SOURCE: + case MADERA_DSP3LMIX_INPUT_4_VOLUME: + case MADERA_DSP3RMIX_INPUT_1_SOURCE: + case MADERA_DSP3RMIX_INPUT_1_VOLUME: + case MADERA_DSP3RMIX_INPUT_2_SOURCE: + case MADERA_DSP3RMIX_INPUT_2_VOLUME: + case MADERA_DSP3RMIX_INPUT_3_SOURCE: + case MADERA_DSP3RMIX_INPUT_3_VOLUME: + case MADERA_DSP3RMIX_INPUT_4_SOURCE: + case MADERA_DSP3RMIX_INPUT_4_VOLUME: + case MADERA_DSP3AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP4LMIX_INPUT_1_SOURCE: + case MADERA_DSP4LMIX_INPUT_1_VOLUME: + case MADERA_DSP4LMIX_INPUT_2_SOURCE: + case MADERA_DSP4LMIX_INPUT_2_VOLUME: + case MADERA_DSP4LMIX_INPUT_3_SOURCE: + case MADERA_DSP4LMIX_INPUT_3_VOLUME: + case MADERA_DSP4LMIX_INPUT_4_SOURCE: + case MADERA_DSP4LMIX_INPUT_4_VOLUME: + case MADERA_DSP4RMIX_INPUT_1_SOURCE: + case MADERA_DSP4RMIX_INPUT_1_VOLUME: + case MADERA_DSP4RMIX_INPUT_2_SOURCE: + case MADERA_DSP4RMIX_INPUT_2_VOLUME: + case MADERA_DSP4RMIX_INPUT_3_SOURCE: + case MADERA_DSP4RMIX_INPUT_3_VOLUME: + case MADERA_DSP4RMIX_INPUT_4_SOURCE: + case MADERA_DSP4RMIX_INPUT_4_VOLUME: + case MADERA_DSP4AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP5LMIX_INPUT_1_SOURCE: + case MADERA_DSP5LMIX_INPUT_1_VOLUME: + case MADERA_DSP5LMIX_INPUT_2_SOURCE: + case MADERA_DSP5LMIX_INPUT_2_VOLUME: + case MADERA_DSP5LMIX_INPUT_3_SOURCE: + case MADERA_DSP5LMIX_INPUT_3_VOLUME: + case MADERA_DSP5LMIX_INPUT_4_SOURCE: + case MADERA_DSP5LMIX_INPUT_4_VOLUME: + case MADERA_DSP5RMIX_INPUT_1_SOURCE: + case MADERA_DSP5RMIX_INPUT_1_VOLUME: + case MADERA_DSP5RMIX_INPUT_2_SOURCE: + case MADERA_DSP5RMIX_INPUT_2_VOLUME: + case MADERA_DSP5RMIX_INPUT_3_SOURCE: + case MADERA_DSP5RMIX_INPUT_3_VOLUME: + case MADERA_DSP5RMIX_INPUT_4_SOURCE: + case MADERA_DSP5RMIX_INPUT_4_VOLUME: + case MADERA_DSP5AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX6MIX_INPUT_1_SOURCE: + case MADERA_ASRC1_1LMIX_INPUT_1_SOURCE: + case MADERA_ASRC1_1RMIX_INPUT_1_SOURCE: + case MADERA_ASRC1_2LMIX_INPUT_1_SOURCE: + case MADERA_ASRC1_2RMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_1LMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_1RMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_2LMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_2RMIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC3MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC4MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT3MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT4MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC3MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC4MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT3MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT4MIX_INPUT_1_SOURCE: + case MADERA_ISRC3DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC3DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC3INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC3INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC4DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC4DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC4INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC4INT2MIX_INPUT_1_SOURCE: + case MADERA_DSP6LMIX_INPUT_1_SOURCE: + case MADERA_DSP6LMIX_INPUT_1_VOLUME: + case MADERA_DSP6LMIX_INPUT_2_SOURCE: + case MADERA_DSP6LMIX_INPUT_2_VOLUME: + case MADERA_DSP6LMIX_INPUT_3_SOURCE: + case MADERA_DSP6LMIX_INPUT_3_VOLUME: + case MADERA_DSP6LMIX_INPUT_4_SOURCE: + case MADERA_DSP6LMIX_INPUT_4_VOLUME: + case MADERA_DSP6RMIX_INPUT_1_SOURCE: + case MADERA_DSP6RMIX_INPUT_1_VOLUME: + case MADERA_DSP6RMIX_INPUT_2_SOURCE: + case MADERA_DSP6RMIX_INPUT_2_VOLUME: + case MADERA_DSP6RMIX_INPUT_3_SOURCE: + case MADERA_DSP6RMIX_INPUT_3_VOLUME: + case MADERA_DSP6RMIX_INPUT_4_SOURCE: + case MADERA_DSP6RMIX_INPUT_4_VOLUME: + case MADERA_DSP6AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP7LMIX_INPUT_1_SOURCE: + case MADERA_DSP7LMIX_INPUT_1_VOLUME: + case MADERA_DSP7LMIX_INPUT_2_SOURCE: + case MADERA_DSP7LMIX_INPUT_2_VOLUME: + case MADERA_DSP7LMIX_INPUT_3_SOURCE: + case MADERA_DSP7LMIX_INPUT_3_VOLUME: + case MADERA_DSP7LMIX_INPUT_4_SOURCE: + case MADERA_DSP7LMIX_INPUT_4_VOLUME: + case MADERA_DSP7RMIX_INPUT_1_SOURCE: + case MADERA_DSP7RMIX_INPUT_1_VOLUME: + case MADERA_DSP7RMIX_INPUT_2_SOURCE: + case MADERA_DSP7RMIX_INPUT_2_VOLUME: + case MADERA_DSP7RMIX_INPUT_3_SOURCE: + case MADERA_DSP7RMIX_INPUT_3_VOLUME: + case MADERA_DSP7RMIX_INPUT_4_SOURCE: + case MADERA_DSP7RMIX_INPUT_4_VOLUME: + case MADERA_DSP7AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX6MIX_INPUT_1_SOURCE: + case MADERA_FX_CTRL1: + case MADERA_FX_CTRL2: + case MADERA_EQ1_1 ... MADERA_EQ1_21: + case MADERA_EQ2_1 ... MADERA_EQ2_21: + case MADERA_EQ3_1 ... MADERA_EQ3_21: + case MADERA_EQ4_1 ... MADERA_EQ4_21: + case MADERA_DRC1_CTRL1: + case MADERA_DRC1_CTRL2: + case MADERA_DRC1_CTRL3: + case MADERA_DRC1_CTRL4: + case MADERA_DRC1_CTRL5: + case MADERA_DRC2_CTRL1: + case MADERA_DRC2_CTRL2: + case MADERA_DRC2_CTRL3: + case MADERA_DRC2_CTRL4: + case MADERA_DRC2_CTRL5: + case MADERA_HPLPF1_1: + case MADERA_HPLPF1_2: + case MADERA_HPLPF2_1: + case MADERA_HPLPF2_2: + case MADERA_HPLPF3_1: + case MADERA_HPLPF3_2: + case MADERA_HPLPF4_1: + case MADERA_HPLPF4_2: + case MADERA_ASRC1_ENABLE: + case MADERA_ASRC1_STATUS: + case MADERA_ASRC1_RATE1: + case MADERA_ASRC1_RATE2: + case MADERA_ASRC2_ENABLE: + case MADERA_ASRC2_STATUS: + case MADERA_ASRC2_RATE1: + case MADERA_ASRC2_RATE2: + case MADERA_ISRC_1_CTRL_1: + case MADERA_ISRC_1_CTRL_2: + case MADERA_ISRC_1_CTRL_3: + case MADERA_ISRC_2_CTRL_1: + case MADERA_ISRC_2_CTRL_2: + case MADERA_ISRC_2_CTRL_3: + case MADERA_ISRC_3_CTRL_1: + case MADERA_ISRC_3_CTRL_2: + case MADERA_ISRC_3_CTRL_3: + case MADERA_ISRC_4_CTRL_1: + case MADERA_ISRC_4_CTRL_2: + case MADERA_ISRC_4_CTRL_3: + case MADERA_CLOCK_CONTROL: + case MADERA_ANC_SRC: + case MADERA_DSP_STATUS: + case MADERA_ANC_COEFF_START ... MADERA_ANC_COEFF_END: + case MADERA_FCL_FILTER_CONTROL: + case MADERA_FCL_ADC_REFORMATTER_CONTROL: + case MADERA_FCL_COEFF_START ... MADERA_FCL_COEFF_END: + case MADERA_FCR_FILTER_CONTROL: + case MADERA_FCR_ADC_REFORMATTER_CONTROL: + case MADERA_FCR_COEFF_START ... MADERA_FCR_COEFF_END: + case MADERA_DAC_COMP_1: + case MADERA_DAC_COMP_2: + case MADERA_FRF_COEFFICIENT_1L_1: + case MADERA_FRF_COEFFICIENT_1L_2: + case MADERA_FRF_COEFFICIENT_1L_3: + case MADERA_FRF_COEFFICIENT_1L_4: + case MADERA_FRF_COEFFICIENT_1R_1: + case MADERA_FRF_COEFFICIENT_1R_2: + case MADERA_FRF_COEFFICIENT_1R_3: + case MADERA_FRF_COEFFICIENT_1R_4: + case MADERA_FRF_COEFFICIENT_2L_1: + case MADERA_FRF_COEFFICIENT_2L_2: + case MADERA_FRF_COEFFICIENT_2L_3: + case MADERA_FRF_COEFFICIENT_2L_4: + case MADERA_FRF_COEFFICIENT_2R_1: + case MADERA_FRF_COEFFICIENT_2R_2: + case MADERA_FRF_COEFFICIENT_2R_3: + case MADERA_FRF_COEFFICIENT_2R_4: + case MADERA_FRF_COEFFICIENT_3L_1: + case MADERA_FRF_COEFFICIENT_3L_2: + case MADERA_FRF_COEFFICIENT_3L_3: + case MADERA_FRF_COEFFICIENT_3L_4: + case MADERA_FRF_COEFFICIENT_3R_1: + case MADERA_FRF_COEFFICIENT_3R_2: + case MADERA_FRF_COEFFICIENT_3R_3: + case MADERA_FRF_COEFFICIENT_3R_4: + case MADERA_FRF_COEFFICIENT_4L_1: + case MADERA_FRF_COEFFICIENT_4L_2: + case MADERA_FRF_COEFFICIENT_4L_3: + case MADERA_FRF_COEFFICIENT_4L_4: + case MADERA_FRF_COEFFICIENT_4R_1: + case MADERA_FRF_COEFFICIENT_4R_2: + case MADERA_FRF_COEFFICIENT_4R_3: + case MADERA_FRF_COEFFICIENT_4R_4: + case MADERA_FRF_COEFFICIENT_5L_1: + case MADERA_FRF_COEFFICIENT_5L_2: + case MADERA_FRF_COEFFICIENT_5L_3: + case MADERA_FRF_COEFFICIENT_5L_4: + case MADERA_FRF_COEFFICIENT_5R_1: + case MADERA_FRF_COEFFICIENT_5R_2: + case MADERA_FRF_COEFFICIENT_5R_3: + case MADERA_FRF_COEFFICIENT_5R_4: + case MADERA_FRF_COEFFICIENT_6L_1: + case MADERA_FRF_COEFFICIENT_6L_2: + case MADERA_FRF_COEFFICIENT_6L_3: + case MADERA_FRF_COEFFICIENT_6L_4: + case MADERA_FRF_COEFFICIENT_6R_1: + case MADERA_FRF_COEFFICIENT_6R_2: + case MADERA_FRF_COEFFICIENT_6R_3: + case MADERA_FRF_COEFFICIENT_6R_4: + case MADERA_GPIO1_CTRL_1 ... MADERA_GPIO40_CTRL_2: + case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33: + case MADERA_IRQ1_MASK_1 ... MADERA_IRQ1_MASK_33: + case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33: + case MADERA_INTERRUPT_DEBOUNCE_7: + case MADERA_IRQ1_CTRL: + return true; + default: + return false; + } +} + +static bool cs47l85_16bit_volatile_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_SOFTWARE_RESET: + case MADERA_HARDWARE_REVISION: + case MADERA_WRITE_SEQUENCER_CTRL_0: + case MADERA_WRITE_SEQUENCER_CTRL_1: + case MADERA_WRITE_SEQUENCER_CTRL_2: + case MADERA_HAPTICS_STATUS: + case MADERA_SAMPLE_RATE_1_STATUS: + case MADERA_SAMPLE_RATE_2_STATUS: + case MADERA_SAMPLE_RATE_3_STATUS: + case MADERA_ASYNC_SAMPLE_RATE_1_STATUS: + case MADERA_ASYNC_SAMPLE_RATE_2_STATUS: + case MADERA_HP_CTRL_1L: + case MADERA_HP_CTRL_1R: + case MADERA_HP_CTRL_2L: + case MADERA_HP_CTRL_2R: + case MADERA_HP_CTRL_3L: + case MADERA_HP_CTRL_3R: + case MADERA_DCS_HP1L_CONTROL: + case MADERA_DCS_HP1R_CONTROL: + case MADERA_MIC_DETECT_1_CONTROL_3: + case MADERA_MIC_DETECT_1_CONTROL_4: + case MADERA_HEADPHONE_DETECT_2: + case MADERA_HEADPHONE_DETECT_3: + case MADERA_HEADPHONE_DETECT_5: + case MADERA_INPUT_ENABLES_STATUS: + case MADERA_OUTPUT_STATUS_1: + case MADERA_RAW_OUTPUT_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_2: + case MADERA_SPD1_TX_CHANNEL_STATUS_3: + case MADERA_SLIMBUS_RX_PORT_STATUS: + case MADERA_SLIMBUS_TX_PORT_STATUS: + case MADERA_FX_CTRL2: + case MADERA_ASRC2_STATUS: + case MADERA_ASRC1_STATUS: + case MADERA_CLOCK_CONTROL: + case MADERA_IRQ1_STATUS_1 ...MADERA_IRQ1_STATUS_33: + case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33: + return true; + default: + return false; + } +} + +static bool cs47l85_32bit_readable_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_508: + case CS47L85_OTP_HPDET_CAL_1 ... CS47L85_OTP_HPDET_CAL_2: + case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_SCRATCH_2: + case MADERA_DSP2_CONFIG_1 ... MADERA_DSP2_SCRATCH_2: + case MADERA_DSP3_CONFIG_1 ... MADERA_DSP3_SCRATCH_2: + case MADERA_DSP4_CONFIG_1 ... MADERA_DSP4_SCRATCH_2: + case MADERA_DSP5_CONFIG_1 ... MADERA_DSP5_SCRATCH_2: + case MADERA_DSP6_CONFIG_1 ... MADERA_DSP6_SCRATCH_2: + case MADERA_DSP7_CONFIG_1 ... MADERA_DSP7_SCRATCH_2: + return true; + default: + return cs47l85_is_adsp_memory(reg); + } +} + +static bool cs47l85_32bit_volatile_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_508: + case CS47L85_OTP_HPDET_CAL_1 ... CS47L85_OTP_HPDET_CAL_2: + case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_SCRATCH_2: + case MADERA_DSP2_CONFIG_1 ... MADERA_DSP2_SCRATCH_2: + case MADERA_DSP3_CONFIG_1 ... MADERA_DSP3_SCRATCH_2: + case MADERA_DSP4_CONFIG_1 ... MADERA_DSP4_SCRATCH_2: + case MADERA_DSP5_CONFIG_1 ... MADERA_DSP5_SCRATCH_2: + case MADERA_DSP6_CONFIG_1 ... MADERA_DSP6_SCRATCH_2: + case MADERA_DSP7_CONFIG_1 ... MADERA_DSP7_SCRATCH_2: + return true; + default: + return cs47l85_is_adsp_memory(reg); + } +} + +const struct regmap_config cs47l85_16bit_spi_regmap = { + .name = "cs47l85_16bit", + .reg_bits = 32, + .pad_bits = 16, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = 0x2fff, + .readable_reg = cs47l85_16bit_readable_register, + .volatile_reg = cs47l85_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = cs47l85_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs47l85_reg_default), +}; +EXPORT_SYMBOL_GPL(cs47l85_16bit_spi_regmap); + +const struct regmap_config cs47l85_16bit_i2c_regmap = { + .name = "cs47l85_16bit", + .reg_bits = 32, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = 0x2fff, + .readable_reg = cs47l85_16bit_readable_register, + .volatile_reg = cs47l85_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = cs47l85_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs47l85_reg_default), +}; +EXPORT_SYMBOL_GPL(cs47l85_16bit_i2c_regmap); + +const struct regmap_config cs47l85_32bit_spi_regmap = { + .name = "cs47l85_32bit", + .reg_bits = 32, + .reg_stride = 2, + .pad_bits = 16, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_DSP7_SCRATCH_2, + .readable_reg = cs47l85_32bit_readable_register, + .volatile_reg = cs47l85_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs47l85_32bit_spi_regmap); + +const struct regmap_config cs47l85_32bit_i2c_regmap = { + .name = "cs47l85_32bit", + .reg_bits = 32, + .reg_stride = 2, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_DSP7_SCRATCH_2, + .readable_reg = cs47l85_32bit_readable_register, + .volatile_reg = cs47l85_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs47l85_32bit_i2c_regmap); diff --git a/drivers/mfd/cs47l90-tables.c b/drivers/mfd/cs47l90-tables.c new file mode 100644 index 000000000000..77207d98f0cc --- /dev/null +++ b/drivers/mfd/cs47l90-tables.c @@ -0,0 +1,2674 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Regmap tables for CS47L90 codec + * + * Copyright (C) 2015-2017 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/registers.h> + +#include "madera.h" + +static const struct reg_sequence cs47l90_reva_16_patch[] = { + { 0x8A, 0x5555 }, + { 0x8A, 0xAAAA }, + { 0x4CF, 0x0700 }, + { 0x171, 0x0003 }, + { 0x101, 0x0444 }, + { 0x159, 0x0002 }, + { 0x120, 0x0444 }, + { 0x1D1, 0x0004 }, + { 0x1E0, 0xC084 }, + { 0x159, 0x0000 }, + { 0x120, 0x0404 }, + { 0x101, 0x0404 }, + { 0x171, 0x0002 }, + { 0x17A, 0x2906 }, + { 0x19A, 0x2906 }, + { 0x441, 0xC750 }, + { 0x340, 0x0001 }, + { 0x112, 0x0405 }, + { 0x124, 0x0C49 }, + { 0x1300, 0x050E }, + { 0x1302, 0x0101 }, + { 0x1380, 0x0425 }, + { 0x1381, 0xF6D8 }, + { 0x1382, 0x0632 }, + { 0x1383, 0xFEC8 }, + { 0x1390, 0x042F }, + { 0x1391, 0xF6CA }, + { 0x1392, 0x0637 }, + { 0x1393, 0xFEC8 }, + { 0x281, 0x0000 }, + { 0x282, 0x0000 }, + { 0x4EA, 0x0100 }, + { 0x8A, 0xCCCC }, + { 0x8A, 0x3333 }, +}; + +int cs47l90_patch(struct madera *madera) +{ + int ret; + + ret = regmap_register_patch(madera->regmap, + cs47l90_reva_16_patch, + ARRAY_SIZE(cs47l90_reva_16_patch)); + if (ret < 0) { + dev_err(madera->dev, + "Error in applying 16-bit patch: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cs47l90_patch); + +static const struct reg_default cs47l90_reg_default[] = { + { 0x00000020, 0x0000 }, /* R32 (0x20) - Tone Generator 1 */ + { 0x00000021, 0x1000 }, /* R33 (0x21) - Tone Generator 2 */ + { 0x00000022, 0x0000 }, /* R34 (0x22) - Tone Generator 3 */ + { 0x00000023, 0x1000 }, /* R35 (0x23) - Tone Generator 4 */ + { 0x00000024, 0x0000 }, /* R36 (0x24) - Tone Generator 5 */ + { 0x00000030, 0x0000 }, /* R48 (0x30) - PWM Drive 1 */ + { 0x00000031, 0x0100 }, /* R49 (0x31) - PWM Drive 2 */ + { 0x00000032, 0x0100 }, /* R50 (0x32) - PWM Drive 3 */ + { 0x00000061, 0x01ff }, /* R97 (0x61) - Sample Rate Sequence Select 1 */ + { 0x00000062, 0x01ff }, /* R98 (0x62) - Sample Rate Sequence Select 2 */ + { 0x00000063, 0x01ff }, /* R99 (0x63) - Sample Rate Sequence Select 3 */ + { 0x00000064, 0x01ff }, /* R100 (0x64) - Sample Rate Sequence Select 4 */ + { 0x00000066, 0x01ff }, /* R102 (0x66) - Always On Triggers Sequence Select 1 */ + { 0x00000067, 0x01ff }, /* R103 (0x67) - Always On Triggers Sequence Select 2 */ + { 0x00000090, 0x0000 }, /* R144 (0x90) - Haptics Control 1 */ + { 0x00000091, 0x7fff }, /* R145 (0x91) - Haptics Control 2 */ + { 0x00000092, 0x0000 }, /* R146 (0x92) - Haptics phase 1 intensity */ + { 0x00000093, 0x0000 }, /* R147 (0x93) - Haptics phase 1 duration */ + { 0x00000094, 0x0000 }, /* R148 (0x94) - Haptics phase 2 intensity */ + { 0x00000095, 0x0000 }, /* R149 (0x95) - Haptics phase 2 duration */ + { 0x00000096, 0x0000 }, /* R150 (0x96) - Haptics phase 3 intensity */ + { 0x00000097, 0x0000 }, /* R151 (0x97) - Haptics phase 3 duration */ + { 0x000000a0, 0x0000 }, /* R160 (0xa0) - Comfort Noise Generator */ + { 0x00000100, 0x0002 }, /* R256 (0x100) - Clock 32k 1 */ + { 0x00000101, 0x0404 }, /* R257 (0x101) - System Clock 1 */ + { 0x00000102, 0x0011 }, /* R258 (0x102) - Sample rate 1 */ + { 0x00000103, 0x0011 }, /* R259 (0x103) - Sample rate 2 */ + { 0x00000104, 0x0011 }, /* R260 (0x104) - Sample rate 3 */ + { 0x00000112, 0x0405 }, /* R274 (0x112) - Async clock 1 */ + { 0x00000113, 0x0011 }, /* R275 (0x113) - Async sample rate 1 */ + { 0x00000114, 0x0011 }, /* R276 (0x114) - Async sample rate 2 */ + { 0x00000120, 0x0404 }, /* R288 (0x120) - DSP Clock 1 */ + { 0x00000122, 0x0000 }, /* R290 (0x122) - DSP Clock 2 */ + { 0x00000149, 0x0000 }, /* R329 (0x149) - Output system clock */ + { 0x0000014a, 0x0000 }, /* R330 (0x14a) - Output async clock */ + { 0x00000152, 0x0000 }, /* R338 (0x152) - Rate Estimator 1 */ + { 0x00000153, 0x0000 }, /* R339 (0x153) - Rate Estimator 2 */ + { 0x00000154, 0x0000 }, /* R340 (0x154) - Rate Estimator 3 */ + { 0x00000155, 0x0000 }, /* R341 (0x155) - Rate Estimator 4 */ + { 0x00000156, 0x0000 }, /* R342 (0x156) - Rate Estimator 5 */ + { 0x00000171, 0x0002 }, /* R369 (0x171) - FLL1 Control 1 */ + { 0x00000172, 0x0008 }, /* R370 (0x172) - FLL1 Control 2 */ + { 0x00000173, 0x0018 }, /* R371 (0x173) - FLL1 Control 3 */ + { 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */ + { 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */ + { 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */ + { 0x00000177, 0x0281 }, /* R375 (0x177) - FLL1 Loop Filter Test 1 */ + { 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */ + { 0x0000017a, 0x2906 }, /* R377 (0x17a) - FLL1 Efs 2 */ + { 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 1 */ + { 0x00000182, 0x0000 }, /* R386 (0x182) - FLL1 Synchroniser 2 */ + { 0x00000183, 0x0000 }, /* R387 (0x183) - FLL1 Synchroniser 3 */ + { 0x00000184, 0x0000 }, /* R388 (0x184) - FLL1 Synchroniser 4 */ + { 0x00000185, 0x0000 }, /* R389 (0x185) - FLL1 Synchroniser 5 */ + { 0x00000186, 0x0000 }, /* R390 (0x186) - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R391 (0x187) - FLL1 Synchroniser 7 */ + { 0x00000189, 0x0000 }, /* R393 (0x189) - FLL1 Spread Spectrum */ + { 0x0000018a, 0x0004 }, /* R394 (0x18a) - FLL1 GPIO Clock */ + { 0x00000191, 0x0002 }, /* R401 (0x191) - FLL2 Control 1 */ + { 0x00000192, 0x0008 }, /* R402 (0x192) - FLL2 Control 2 */ + { 0x00000193, 0x0018 }, /* R403 (0x193) - FLL2 Control 3 */ + { 0x00000194, 0x007d }, /* R404 (0x194) - FLL2 Control 4 */ + { 0x00000195, 0x0000 }, /* R405 (0x195) - FLL2 Control 5 */ + { 0x00000196, 0x0000 }, /* R406 (0x196) - FLL2 Control 6 */ + { 0x00000197, 0x0281 }, /* R407 (0x197) - FLL2 Loop Filter Test 1 */ + { 0x00000199, 0x0000 }, /* R409 (0x199) - FLL2 Control 7 */ + { 0x0000019a, 0x2906 }, /* R410 (0x19a) - FLL2 Efs 2 */ + { 0x000001a1, 0x0000 }, /* R417 (0x1a1) - FLL2 Synchroniser 1 */ + { 0x000001a2, 0x0000 }, /* R418 (0x1a2) - FLL2 Synchroniser 2 */ + { 0x000001a3, 0x0000 }, /* R419 (0x1a3) - FLL2 Synchroniser 3 */ + { 0x000001a4, 0x0000 }, /* R420 (0x1a4) - FLL2 Synchroniser 4 */ + { 0x000001a5, 0x0000 }, /* R421 (0x1a5) - FLL2 Synchroniser 5 */ + { 0x000001a6, 0x0000 }, /* R422 (0x1a6) - FLL2 Synchroniser 6 */ + { 0x000001a7, 0x0001 }, /* R423 (0x1a7) - FLL2 Synchroniser 7 */ + { 0x000001a9, 0x0000 }, /* R425 (0x1a9) - FLL2 Spread Spectrum */ + { 0x000001aa, 0x0004 }, /* R426 (0x1aa) - FLL2 GPIO Clock */ + { 0x000001d1, 0x0004 }, /* R465 (0x1d1) - FLLAO_CONTROL_1 */ + { 0x000001d2, 0x0004 }, /* R466 (0x1d2) - FLLAO_CONTROL_2 */ + { 0x000001d3, 0x0000 }, /* R467 (0x1d3) - FLLAO_CONTROL_3 */ + { 0x000001d4, 0x0000 }, /* R468 (0x1d4) - FLLAO_CONTROL_4 */ + { 0x000001d5, 0x0001 }, /* R469 (0x1d5) - FLLAO_CONTROL_5 */ + { 0x000001d6, 0x8004 }, /* R470 (0x1d6) - FLLAO_CONTROL_6 */ + { 0x000001d8, 0x0000 }, /* R472 (0x1d8) - FLLAO_CONTROL_7 */ + { 0x000001da, 0x0070 }, /* R474 (0x1da) - FLLAO_CONTROL_8 */ + { 0x000001db, 0x0000 }, /* R475 (0x1db) - FLLAO_CONTROL_9 */ + { 0x000001dc, 0x06da }, /* R476 (0x1dc) - FLLAO_CONTROL_10 */ + { 0x000001dd, 0x0011 }, /* R477 (0x1dd) - FLLAO_CONTROL_11 */ + { 0x00000200, 0x0006 }, /* R512 (0x200) - Mic Charge Pump 1 */ + { 0x00000213, 0x03e4 }, /* R531 (0x213) - LDO2 Control 1 */ + { 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */ + { 0x00000219, 0x00e6 }, /* R537 (0x219) - Mic Bias Ctrl 2 */ + { 0x0000021c, 0x2222 }, /* R540 (0x21c) - Mic Bias Ctrl 5 */ + { 0x0000021e, 0x2222 }, /* R542 (0x21e) - Mic Bias Ctrl 6 */ + { 0x0000027e, 0x0000 }, /* R638 (0x27e) - EDRE HP stereo control */ + { 0x00000293, 0x0080 }, /* R659 (0x293) - Accessory Detect Mode 1 */ + { 0x00000299, 0x0000 }, /* R665 (0x299) - Headphone Detect 0 */ + { 0x0000029b, 0x0000 }, /* R667 (0x29b) - Headphone Detect 1 */ + { 0x000002a2, 0x0010 }, /* R674 (0x2a2) - Mic Detect 1 Control 0 */ + { 0x000002a3, 0x1102 }, /* R675 (0x2a3) - Mic Detect 1 Control 1 */ + { 0x000002a4, 0x009f }, /* R676 (0x2a4) - Mic Detect 1 Control 2 */ + { 0x000002a6, 0x3d3d }, /* R678 (0x2a6) - Mic Detect 1 Level 1 */ + { 0x000002a7, 0x3d3d }, /* R679 (0x2a7) - Mic Detect 1 Level 2 */ + { 0x000002a8, 0x333d }, /* R680 (0x2a8) - Mic Detect 1 Level 3 */ + { 0x000002a9, 0x202d }, /* R681 (0x2a9) - Mic Detect 1 Level 4 */ + { 0x000002b2, 0x0010 }, /* R690 (0x2b2) - Mic Detect 2 Control 0 */ + { 0x000002b3, 0x1102 }, /* R691 (0x2b3) - Mic Detect 2 Control 1 */ + { 0x000002b4, 0x009f }, /* R692 (0x2b4) - Mic Detect 2 Control 2 */ + { 0x000002b6, 0x3d3d }, /* R694 (0x2b6) - Mic Detect 2 Level 1 */ + { 0x000002b7, 0x3d3d }, /* R695 (0x2b7) - Mic Detect 2 Level 2 */ + { 0x000002b8, 0x333d }, /* R696 (0x2b8) - Mic Detect 2 Level 3 */ + { 0x000002b9, 0x202d }, /* R697 (0x2b9) - Mic Detect 2 Level 4 */ + { 0x000002c6, 0x0010 }, /* R710 (0x2c6) - Mic Clamp control */ + { 0x000002c8, 0x0000 }, /* R712 (0x2c8) - GP switch 1 */ + { 0x000002d3, 0x0000 }, /* R723 (0x2d3) - Jack detect analogue */ + { 0x00000300, 0x0000 }, /* R768 (0x300) - Input Enables */ + { 0x00000308, 0x0400 }, /* R776 (0x308) - Input Rate */ + { 0x00000309, 0x0022 }, /* R777 (0x309) - Input Volume Ramp */ + { 0x0000030c, 0x0002 }, /* R780 (0x30C) - HPF Control */ + { 0x00000310, 0x0080 }, /* R784 (0x310) - IN1L Control */ + { 0x00000311, 0x0180 }, /* R785 (0x311) - ADC Digital Volume 1L */ + { 0x00000312, 0x0500 }, /* R786 (0x312) - DMIC1L Control */ + { 0x00000313, 0x0000 }, /* R787 (0x313) - IN1L Rate Control */ + { 0x00000314, 0x0080 }, /* R788 (0x314) - IN1R Control */ + { 0x00000315, 0x0180 }, /* R789 (0x315) - ADC Digital Volume 1R */ + { 0x00000316, 0x0000 }, /* R790 (0x316) - DMIC1R Control */ + { 0x00000317, 0x0000 }, /* R791 (0x317) - IN1R Rate Control */ + { 0x00000318, 0x0080 }, /* R792 (0x318) - IN2L Control */ + { 0x00000319, 0x0180 }, /* R793 (0x319) - ADC Digital Volume 2L */ + { 0x0000031a, 0x0500 }, /* R794 (0x31a) - DMIC2L Control */ + { 0x0000031b, 0x0000 }, /* R795 (0x31b) - IN2L Rate Control */ + { 0x0000031c, 0x0080 }, /* R796 (0x31c) - IN2R Control */ + { 0x0000031d, 0x0180 }, /* R797 (0x31d) - ADC Digital Volume 2R */ + { 0x0000031e, 0x0000 }, /* R798 (0x31e) - DMIC2R Control */ + { 0x0000031f, 0x0000 }, /* R799 (0x31f) - IN2R Rate Control */ + { 0x00000320, 0x0000 }, /* R800 (0x320) - IN3L Control */ + { 0x00000321, 0x0180 }, /* R801 (0x321) - ADC Digital Volume 3L */ + { 0x00000322, 0x0500 }, /* R802 (0x322) - DMIC3L Control */ + { 0x00000323, 0x0000 }, /* R803 (0x323) - IN3L Rate Control */ + { 0x00000324, 0x0000 }, /* R804 (0x324) - IN3R Control */ + { 0x00000325, 0x0180 }, /* R805 (0x325) - ADC Digital Volume 3R */ + { 0x00000326, 0x0000 }, /* R806 (0x326) - DMIC3R Control */ + { 0x00000327, 0x0000 }, /* R807 (0x327) - IN3R Rate Control */ + { 0x00000328, 0x0000 }, /* R808 (0x328) - IN4 Control */ + { 0x00000329, 0x0180 }, /* R809 (0x329) - ADC Digital Volume 4L */ + { 0x0000032a, 0x0500 }, /* R810 (0x32a) - DMIC4L Control */ + { 0x0000032b, 0x0000 }, /* R811 (0x32b) - IN4L Rate Control */ + { 0x0000032c, 0x0000 }, /* R812 (0x32c) - IN4R Control */ + { 0x0000032d, 0x0180 }, /* R813 (0x32d) - ADC Digital Volume 4R */ + { 0x0000032e, 0x0000 }, /* R814 (0x32e) - DMIC4R Control */ + { 0x0000032f, 0x0000 }, /* R815 (0x32f) - IN4R Rate Control */ + { 0x00000330, 0x0000 }, /* R816 (0x330) - IN5L Control */ + { 0x00000331, 0x0180 }, /* R817 (0x331) - ADC Digital Volume 5L */ + { 0x00000332, 0x0500 }, /* R818 (0x332) - DMIC5L Control */ + { 0x00000333, 0x0000 }, /* R819 (0x333) - IN5L Rate Control */ + { 0x00000334, 0x0000 }, /* R820 (0x334) - IN5R Control */ + { 0x00000335, 0x0180 }, /* R821 (0x335) - ADC Digital Volume 5R */ + { 0x00000336, 0x0000 }, /* R822 (0x336) - DMIC5R Control */ + { 0x00000337, 0x0000 }, /* R823 (0x337) - IN5R Rate Control */ + { 0x00000400, 0x0000 }, /* R1024 (0x400) - Output Enables 1 */ + { 0x00000408, 0x0000 }, /* R1032 (0x408) - Output Rate 1 */ + { 0x00000409, 0x0022 }, /* R1033 (0x409) - Output Volume Ramp */ + { 0x00000410, 0x0080 }, /* R1040 (0x410) - Output Path Config 1L */ + { 0x00000411, 0x0180 }, /* R1041 (0x411) - DAC Digital Volume 1L */ + { 0x00000412, 0x0000 }, /* R1042 (0x412) - Output Path Config 1 */ + { 0x00000413, 0x0001 }, /* R1043 (0x413) - Noise Gate Select 1L */ + { 0x00000414, 0x0080 }, /* R1044 (0x414) - Output Path Config 1R */ + { 0x00000415, 0x0180 }, /* R1045 (0x415) - DAC Digital Volume 1R */ + { 0x00000417, 0x0002 }, /* R1047 (0x417) - Noise Gate Select 1R */ + { 0x00000418, 0x0080 }, /* R1048 (0x418) - Output Path Config 2L */ + { 0x00000419, 0x0180 }, /* R1049 (0x419) - DAC Digital Volume 2L */ + { 0x0000041a, 0x0002 }, /* R1050 (0x41a) - Output Path Config 2 */ + { 0x0000041b, 0x0004 }, /* R1051 (0x41b) - Noise Gate Select 2L */ + { 0x0000041c, 0x0080 }, /* R1052 (0x41c) - Output Path Config 2R */ + { 0x0000041d, 0x0180 }, /* R1053 (0x41d) - DAC Digital Volume 2R */ + { 0x0000041f, 0x0008 }, /* R1055 (0x41f) - Noise Gate Select 2R */ + { 0x00000420, 0x0080 }, /* R1056 (0x420) - Output Path Config 3L */ + { 0x00000421, 0x0180 }, /* R1057 (0x421) - DAC Digital Volume 3L */ + { 0x00000423, 0x0010 }, /* R1059 (0x423) - Noise Gate Select 3L */ + { 0x00000424, 0x0080 }, /* R1060 (0x424) - Output Path Config 3R */ + { 0x00000425, 0x0180 }, /* R1061 (0x425) - DAC Digital Volume 3R */ + { 0x00000427, 0x0020 }, /* R1063 (0x427) - Noise Gate Select 3R */ + { 0x00000430, 0x0000 }, /* R1072 (0x430) - Output Path Config 5L */ + { 0x00000431, 0x0180 }, /* R1073 (0x431) - DAC Digital Volume 5L */ + { 0x00000433, 0x0100 }, /* R1075 (0x433) - Noise Gate Select 5L */ + { 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */ + { 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */ + { 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */ + { 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */ + { 0x00000448, 0x003f }, /* R1096 (0x448) - eDRE Enable */ + { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ + { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ + { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ + { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ + { 0x000004a0, 0x3080 }, /* R1184 (0x4a0) - HP1 Short Circuit Ctrl */ + { 0x000004a1, 0x3000 }, /* R1185 (0x4a1) - HP2 Short Circuit Ctrl */ + { 0x000004a2, 0x3000 }, /* R1186 (0x4a2) - HP3 Short Circuit Ctrl */ + { 0x00000500, 0x000c }, /* R1280 (0x500) - AIF1 BCLK Ctrl */ + { 0x00000501, 0x0000 }, /* R1281 (0x501) - AIF1 Tx Pin Ctrl */ + { 0x00000502, 0x0000 }, /* R1282 (0x502) - AIF1 Rx Pin Ctrl */ + { 0x00000503, 0x0000 }, /* R1283 (0x503) - AIF1 Rate Ctrl */ + { 0x00000504, 0x0000 }, /* R1284 (0x504) - AIF1 Format */ + { 0x00000506, 0x0040 }, /* R1286 (0x506) - AIF1 Rx BCLK Rate */ + { 0x00000507, 0x1818 }, /* R1287 (0x507) - AIF1 Frame Ctrl 1 */ + { 0x00000508, 0x1818 }, /* R1288 (0x508) - AIF1 Frame Ctrl 2 */ + { 0x00000509, 0x0000 }, /* R1289 (0x509) - AIF1 Frame Ctrl 3 */ + { 0x0000050a, 0x0001 }, /* R1290 (0x50a) - AIF1 Frame Ctrl 4 */ + { 0x0000050b, 0x0002 }, /* R1291 (0x50b) - AIF1 Frame Ctrl 5 */ + { 0x0000050c, 0x0003 }, /* R1292 (0x50c) - AIF1 Frame Ctrl 6 */ + { 0x0000050d, 0x0004 }, /* R1293 (0x50d) - AIF1 Frame Ctrl 7 */ + { 0x0000050e, 0x0005 }, /* R1294 (0x50e) - AIF1 Frame Ctrl 8 */ + { 0x0000050f, 0x0006 }, /* R1295 (0x50f) - AIF1 Frame Ctrl 9 */ + { 0x00000510, 0x0007 }, /* R1296 (0x510) - AIF1 Frame Ctrl 10 */ + { 0x00000511, 0x0000 }, /* R1297 (0x511) - AIF1 Frame Ctrl 11 */ + { 0x00000512, 0x0001 }, /* R1298 (0x512) - AIF1 Frame Ctrl 12 */ + { 0x00000513, 0x0002 }, /* R1299 (0x513) - AIF1 Frame Ctrl 13 */ + { 0x00000514, 0x0003 }, /* R1300 (0x514) - AIF1 Frame Ctrl 14 */ + { 0x00000515, 0x0004 }, /* R1301 (0x515) - AIF1 Frame Ctrl 15 */ + { 0x00000516, 0x0005 }, /* R1302 (0x516) - AIF1 Frame Ctrl 16 */ + { 0x00000517, 0x0006 }, /* R1303 (0x517) - AIF1 Frame Ctrl 17 */ + { 0x00000518, 0x0007 }, /* R1304 (0x518) - AIF1 Frame Ctrl 18 */ + { 0x00000519, 0x0000 }, /* R1305 (0x519) - AIF1 Tx Enables */ + { 0x0000051a, 0x0000 }, /* R1306 (0x51a) - AIF1 Rx Enables */ + { 0x00000540, 0x000c }, /* R1344 (0x540) - AIF2 BCLK Ctrl */ + { 0x00000541, 0x0000 }, /* R1345 (0x541) - AIF2 Tx Pin Ctrl */ + { 0x00000542, 0x0000 }, /* R1346 (0x542) - AIF2 Rx Pin Ctrl */ + { 0x00000543, 0x0000 }, /* R1347 (0x543) - AIF2 Rate Ctrl */ + { 0x00000544, 0x0000 }, /* R1348 (0x544) - AIF2 Format */ + { 0x00000546, 0x0040 }, /* R1350 (0x546) - AIF2 Rx BCLK Rate */ + { 0x00000547, 0x1818 }, /* R1351 (0x547) - AIF2 Frame Ctrl 1 */ + { 0x00000548, 0x1818 }, /* R1352 (0x548) - AIF2 Frame Ctrl 2 */ + { 0x00000549, 0x0000 }, /* R1353 (0x549) - AIF2 Frame Ctrl 3 */ + { 0x0000054a, 0x0001 }, /* R1354 (0x54a) - AIF2 Frame Ctrl 4 */ + { 0x0000054b, 0x0002 }, /* R1355 (0x54b) - AIF2 Frame Ctrl 5 */ + { 0x0000054c, 0x0003 }, /* R1356 (0x54c) - AIF2 Frame Ctrl 6 */ + { 0x0000054d, 0x0004 }, /* R1357 (0x54d) - AIF2 Frame Ctrl 7 */ + { 0x0000054e, 0x0005 }, /* R1358 (0x54e) - AIF2 Frame Ctrl 8 */ + { 0x0000054f, 0x0006 }, /* R1359 (0x54f) - AIF2 Frame Ctrl 9 */ + { 0x00000550, 0x0007 }, /* R1360 (0x550) - AIF2 Frame Ctrl 10 */ + { 0x00000551, 0x0000 }, /* R1361 (0x551) - AIF2 Frame Ctrl 11 */ + { 0x00000552, 0x0001 }, /* R1362 (0x552) - AIF2 Frame Ctrl 12 */ + { 0x00000553, 0x0002 }, /* R1363 (0x553) - AIF2 Frame Ctrl 13 */ + { 0x00000554, 0x0003 }, /* R1364 (0x554) - AIF2 Frame Ctrl 14 */ + { 0x00000555, 0x0004 }, /* R1365 (0x555) - AIF2 Frame Ctrl 15 */ + { 0x00000556, 0x0005 }, /* R1366 (0x556) - AIF2 Frame Ctrl 16 */ + { 0x00000557, 0x0006 }, /* R1367 (0x557) - AIF2 Frame Ctrl 17 */ + { 0x00000558, 0x0007 }, /* R1368 (0x558) - AIF2 Frame Ctrl 18 */ + { 0x00000559, 0x0000 }, /* R1369 (0x559) - AIF2 Tx Enables */ + { 0x0000055a, 0x0000 }, /* R1370 (0x55a) - AIF2 Rx Enables */ + { 0x00000580, 0x000c }, /* R1408 (0x580) - AIF3 BCLK Ctrl */ + { 0x00000581, 0x0000 }, /* R1409 (0x581) - AIF3 Tx Pin Ctrl */ + { 0x00000582, 0x0000 }, /* R1410 (0x582) - AIF3 Rx Pin Ctrl */ + { 0x00000583, 0x0000 }, /* R1411 (0x583) - AIF3 Rate Ctrl */ + { 0x00000584, 0x0000 }, /* R1412 (0x584) - AIF3 Format */ + { 0x00000586, 0x0040 }, /* R1414 (0x586) - AIF3 Rx BCLK Rate */ + { 0x00000587, 0x1818 }, /* R1415 (0x587) - AIF3 Frame Ctrl 1 */ + { 0x00000588, 0x1818 }, /* R1416 (0x588) - AIF3 Frame Ctrl 2 */ + { 0x00000589, 0x0000 }, /* R1417 (0x589) - AIF3 Frame Ctrl 3 */ + { 0x0000058a, 0x0001 }, /* R1418 (0x58a) - AIF3 Frame Ctrl 4 */ + { 0x00000591, 0x0000 }, /* R1425 (0x591) - AIF3 Frame Ctrl 11 */ + { 0x00000592, 0x0001 }, /* R1426 (0x592) - AIF3 Frame Ctrl 12 */ + { 0x00000599, 0x0000 }, /* R1433 (0x599) - AIF3 Tx Enables */ + { 0x0000059a, 0x0000 }, /* R1434 (0x59a) - AIF3 Rx Enables */ + { 0x000005a0, 0x000c }, /* R1440 (0x5a0) - AIF4 BCLK Ctrl */ + { 0x000005a1, 0x0000 }, /* R1441 (0x5a1) - AIF4 Tx Pin Ctrl */ + { 0x000005a2, 0x0000 }, /* R1442 (0x5a2) - AIF4 Rx Pin Ctrl */ + { 0x000005a3, 0x0000 }, /* R1443 (0x5a3) - AIF4 Rate Ctrl */ + { 0x000005a4, 0x0000 }, /* R1444 (0x5a4) - AIF4 Format */ + { 0x000005a6, 0x0040 }, /* R1446 (0x5a6) - AIF4 Rx BCLK Rate */ + { 0x000005a7, 0x1818 }, /* R1447 (0x5a7) - AIF4 Frame Ctrl 1 */ + { 0x000005a8, 0x1818 }, /* R1448 (0x5a8) - AIF4 Frame Ctrl 2 */ + { 0x000005a9, 0x0000 }, /* R1449 (0x5a9) - AIF4 Frame Ctrl 3 */ + { 0x000005aa, 0x0001 }, /* R1450 (0x5aa) - AIF4 Frame Ctrl 4 */ + { 0x000005b1, 0x0000 }, /* R1457 (0x5b1) - AIF4 Frame Ctrl 11 */ + { 0x000005b2, 0x0001 }, /* R1458 (0x5b2) - AIF4 Frame Ctrl 12 */ + { 0x000005b9, 0x0000 }, /* R1465 (0x5b9) - AIF4 Tx Enables */ + { 0x000005ba, 0x0000 }, /* R1466 (0x5ba) - AIF4 Rx Enables */ + { 0x000005c2, 0x0000 }, /* R1474 (0x5c2) - SPD1 TX Control */ + { 0x000005e3, 0x0000 }, /* R1507 (0x5e3) - SLIMbus Framer Ref Gear */ + { 0x000005e5, 0x0000 }, /* R1509 (0x5e5) - SLIMbus Rates 1 */ + { 0x000005e6, 0x0000 }, /* R1510 (0x5e6) - SLIMbus Rates 2 */ + { 0x000005e7, 0x0000 }, /* R1511 (0x5e7) - SLIMbus Rates 3 */ + { 0x000005e8, 0x0000 }, /* R1512 (0x5e8) - SLIMbus Rates 4 */ + { 0x000005e9, 0x0000 }, /* R1513 (0x5e9) - SLIMbus Rates 5 */ + { 0x000005ea, 0x0000 }, /* R1514 (0x5ea) - SLIMbus Rates 6 */ + { 0x000005eb, 0x0000 }, /* R1515 (0x5eb) - SLIMbus Rates 7 */ + { 0x000005ec, 0x0000 }, /* R1516 (0x5ec) - SLIMbus Rates 8 */ + { 0x000005f5, 0x0000 }, /* R1525 (0x5f5) - SLIMbus RX Channel Enable */ + { 0x000005f6, 0x0000 }, /* R1526 (0x5F6) - SLIMbus TX Channel Enable */ + { 0x00000640, 0x0000 }, /* R1600 (0x640) - PWM1MIX Input 1 Source */ + { 0x00000641, 0x0080 }, /* R1601 (0x641) - PWM1MIX Input 1 Volume */ + { 0x00000642, 0x0000 }, /* R1602 (0x642) - PWM1MIX Input 2 Source */ + { 0x00000643, 0x0080 }, /* R1603 (0x643) - PWM1MIX Input 2 Volume */ + { 0x00000644, 0x0000 }, /* R1604 (0x644) - PWM1MIX Input 3 Source */ + { 0x00000645, 0x0080 }, /* R1605 (0x645) - PWM1MIX Input 3 Volume */ + { 0x00000646, 0x0000 }, /* R1606 (0x646) - PWM1MIX Input 4 Source */ + { 0x00000647, 0x0080 }, /* R1607 (0x647) - PWM1MIX Input 4 Volume */ + { 0x00000648, 0x0000 }, /* R1608 (0x648) - PWM2MIX Input 1 Source */ + { 0x00000649, 0x0080 }, /* R1609 (0x649) - PWM2MIX Input 1 Volume */ + { 0x0000064a, 0x0000 }, /* R1610 (0x64a) - PWM2MIX Input 2 Source */ + { 0x0000064b, 0x0080 }, /* R1611 (0x64b) - PWM2MIX Input 2 Volume */ + { 0x0000064c, 0x0000 }, /* R1612 (0x64c) - PWM2MIX Input 3 Source */ + { 0x0000064d, 0x0080 }, /* R1613 (0x64d) - PWM2MIX Input 3 Volume */ + { 0x0000064e, 0x0000 }, /* R1614 (0x64e) - PWM2MIX Input 4 Source */ + { 0x0000064f, 0x0080 }, /* R1615 (0x64f) - PWM2MIX Input 4 Volume */ + { 0x00000680, 0x0000 }, /* R1664 (0x680) - OUT1LMIX Input 1 Source */ + { 0x00000681, 0x0080 }, /* R1665 (0x681) - OUT1LMIX Input 1 Volume */ + { 0x00000682, 0x0000 }, /* R1666 (0x682) - OUT1LMIX Input 2 Source */ + { 0x00000683, 0x0080 }, /* R1667 (0x683) - OUT1LMIX Input 2 Volume */ + { 0x00000684, 0x0000 }, /* R1668 (0x684) - OUT1LMIX Input 3 Source */ + { 0x00000685, 0x0080 }, /* R1669 (0x685) - OUT1LMIX Input 3 Volume */ + { 0x00000686, 0x0000 }, /* R1670 (0x686) - OUT1LMIX Input 4 Source */ + { 0x00000687, 0x0080 }, /* R1671 (0x687) - OUT1LMIX Input 4 Volume */ + { 0x00000688, 0x0000 }, /* R1672 (0x688) - OUT1RMIX Input 1 Source */ + { 0x00000689, 0x0080 }, /* R1673 (0x689) - OUT1RMIX Input 1 Volume */ + { 0x0000068a, 0x0000 }, /* R1674 (0x68a) - OUT1RMIX Input 2 Source */ + { 0x0000068b, 0x0080 }, /* R1675 (0x68b) - OUT1RMIX Input 2 Volume */ + { 0x0000068c, 0x0000 }, /* R1672 (0x68c) - OUT1RMIX Input 3 Source */ + { 0x0000068d, 0x0080 }, /* R1673 (0x68d) - OUT1RMIX Input 3 Volume */ + { 0x0000068e, 0x0000 }, /* R1674 (0x68e) - OUT1RMIX Input 4 Source */ + { 0x0000068f, 0x0080 }, /* R1675 (0x68f) - OUT1RMIX Input 4 Volume */ + { 0x00000690, 0x0000 }, /* R1680 (0x690) - OUT2LMIX Input 1 Source */ + { 0x00000691, 0x0080 }, /* R1681 (0x691) - OUT2LMIX Input 1 Volume */ + { 0x00000692, 0x0000 }, /* R1682 (0x692) - OUT2LMIX Input 2 Source */ + { 0x00000693, 0x0080 }, /* R1683 (0x693) - OUT2LMIX Input 2 Volume */ + { 0x00000694, 0x0000 }, /* R1684 (0x694) - OUT2LMIX Input 3 Source */ + { 0x00000695, 0x0080 }, /* R1685 (0x695) - OUT2LMIX Input 3 Volume */ + { 0x00000696, 0x0000 }, /* R1686 (0x696) - OUT2LMIX Input 4 Source */ + { 0x00000697, 0x0080 }, /* R1687 (0x697) - OUT2LMIX Input 4 Volume */ + { 0x00000698, 0x0000 }, /* R1688 (0x698) - OUT2RMIX Input 1 Source */ + { 0x00000699, 0x0080 }, /* R1689 (0x699) - OUT2RMIX Input 1 Volume */ + { 0x0000069a, 0x0000 }, /* R1690 (0x69a) - OUT2RMIX Input 2 Source */ + { 0x0000069b, 0x0080 }, /* R1691 (0x69b) - OUT2RMIX Input 2 Volume */ + { 0x0000069c, 0x0000 }, /* R1692 (0x69c) - OUT2RMIX Input 3 Source */ + { 0x0000069d, 0x0080 }, /* R1693 (0x69d) - OUT2RMIX Input 3 Volume */ + { 0x0000069e, 0x0000 }, /* R1694 (0x69e) - OUT2RMIX Input 4 Source */ + { 0x0000069f, 0x0080 }, /* R1695 (0x69f) - OUT2RMIX Input 4 Volume */ + { 0x000006a0, 0x0000 }, /* R1696 (0x6a0) - OUT3LMIX Input 1 Source */ + { 0x000006a1, 0x0080 }, /* R1697 (0x6a1) - OUT3LMIX Input 1 Volume */ + { 0x000006a2, 0x0000 }, /* R1698 (0x6a2) - OUT3LMIX Input 2 Source */ + { 0x000006a3, 0x0080 }, /* R1699 (0x6a3) - OUT3LMIX Input 2 Volume */ + { 0x000006a4, 0x0000 }, /* R1700 (0x6a4) - OUT3LMIX Input 3 Source */ + { 0x000006a5, 0x0080 }, /* R1701 (0x6a5) - OUT3LMIX Input 3 Volume */ + { 0x000006a6, 0x0000 }, /* R1702 (0x6a6) - OUT3LMIX Input 4 Source */ + { 0x000006a7, 0x0080 }, /* R1703 (0x6a7) - OUT3LMIX Input 4 Volume */ + { 0x000006a8, 0x0000 }, /* R1704 (0x6a8) - OUT3RMIX Input 1 Source */ + { 0x000006a9, 0x0080 }, /* R1705 (0x6a9) - OUT3RMIX Input 1 Volume */ + { 0x000006aa, 0x0000 }, /* R1706 (0x6aa) - OUT3RMIX Input 2 Source */ + { 0x000006ab, 0x0080 }, /* R1707 (0x6ab) - OUT3RMIX Input 2 Volume */ + { 0x000006ac, 0x0000 }, /* R1708 (0x6ac) - OUT3RMIX Input 3 Source */ + { 0x000006ad, 0x0080 }, /* R1709 (0x6ad) - OUT3RMIX Input 3 Volume */ + { 0x000006ae, 0x0000 }, /* R1710 (0x6ae) - OUT3RMIX Input 4 Source */ + { 0x000006af, 0x0080 }, /* R1711 (0x6af) - OUT3RMIX Input 4 Volume */ + { 0x000006c0, 0x0000 }, /* R1728 (0x6c0) - OUT5LMIX Input 1 Source */ + { 0x000006c1, 0x0080 }, /* R1729 (0x6c1) - OUT5LMIX Input 1 Volume */ + { 0x000006c2, 0x0000 }, /* R1730 (0x6c2) - OUT5LMIX Input 2 Source */ + { 0x000006c3, 0x0080 }, /* R1731 (0x6c3) - OUT5LMIX Input 2 Volume */ + { 0x000006c4, 0x0000 }, /* R1732 (0x6c4) - OUT5LMIX Input 3 Source */ + { 0x000006c5, 0x0080 }, /* R1733 (0x6c5) - OUT5LMIX Input 3 Volume */ + { 0x000006c6, 0x0000 }, /* R1734 (0x6c6) - OUT5LMIX Input 4 Source */ + { 0x000006c7, 0x0080 }, /* R1735 (0x6c7) - OUT5LMIX Input 4 Volume */ + { 0x000006c8, 0x0000 }, /* R1736 (0x6c8) - OUT5RMIX Input 1 Source */ + { 0x000006c9, 0x0080 }, /* R1737 (0x6c9) - OUT5RMIX Input 1 Volume */ + { 0x000006ca, 0x0000 }, /* R1738 (0x6ca) - OUT5RMIX Input 2 Source */ + { 0x000006cb, 0x0080 }, /* R1739 (0x6cb) - OUT5RMIX Input 2 Volume */ + { 0x000006cc, 0x0000 }, /* R1740 (0x6cc) - OUT5RMIX Input 3 Source */ + { 0x000006cd, 0x0080 }, /* R1741 (0x6cd) - OUT5RMIX Input 3 Volume */ + { 0x000006ce, 0x0000 }, /* R1742 (0x6ce) - OUT5RMIX Input 4 Source */ + { 0x000006cf, 0x0080 }, /* R1743 (0x6cf) - OUT5RMIX Input 4 Volume */ + { 0x00000700, 0x0000 }, /* R1792 (0x700) - AIF1TX1MIX Input 1 Source */ + { 0x00000701, 0x0080 }, /* R1793 (0x701) - AIF1TX1MIX Input 1 Volume */ + { 0x00000702, 0x0000 }, /* R1794 (0x702) - AIF1TX1MIX Input 2 Source */ + { 0x00000703, 0x0080 }, /* R1795 (0x703) - AIF1TX1MIX Input 2 Volume */ + { 0x00000704, 0x0000 }, /* R1796 (0x704) - AIF1TX1MIX Input 3 Source */ + { 0x00000705, 0x0080 }, /* R1797 (0x705) - AIF1TX1MIX Input 3 Volume */ + { 0x00000706, 0x0000 }, /* R1798 (0x706) - AIF1TX1MIX Input 4 Source */ + { 0x00000707, 0x0080 }, /* R1799 (0x707) - AIF1TX1MIX Input 4 Volume */ + { 0x00000708, 0x0000 }, /* R1800 (0x708) - AIF1TX2MIX Input 1 Source */ + { 0x00000709, 0x0080 }, /* R1801 (0x709) - AIF1TX2MIX Input 1 Volume */ + { 0x0000070a, 0x0000 }, /* R1802 (0x70a) - AIF1TX2MIX Input 2 Source */ + { 0x0000070b, 0x0080 }, /* R1803 (0x70b) - AIF1TX2MIX Input 2 Volume */ + { 0x0000070c, 0x0000 }, /* R1804 (0x70c) - AIF1TX2MIX Input 3 Source */ + { 0x0000070d, 0x0080 }, /* R1805 (0x70d) - AIF1TX2MIX Input 3 Volume */ + { 0x0000070e, 0x0000 }, /* R1806 (0x70e) - AIF1TX2MIX Input 4 Source */ + { 0x0000070f, 0x0080 }, /* R1807 (0x70f) - AIF1TX2MIX Input 4 Volume */ + { 0x00000710, 0x0000 }, /* R1808 (0x710) - AIF1TX3MIX Input 1 Source */ + { 0x00000711, 0x0080 }, /* R1809 (0x711) - AIF1TX3MIX Input 1 Volume */ + { 0x00000712, 0x0000 }, /* R1810 (0x712) - AIF1TX3MIX Input 2 Source */ + { 0x00000713, 0x0080 }, /* R1811 (0x713) - AIF1TX3MIX Input 2 Volume */ + { 0x00000714, 0x0000 }, /* R1812 (0x714) - AIF1TX3MIX Input 3 Source */ + { 0x00000715, 0x0080 }, /* R1813 (0x715) - AIF1TX3MIX Input 3 Volume */ + { 0x00000716, 0x0000 }, /* R1814 (0x716) - AIF1TX3MIX Input 4 Source */ + { 0x00000717, 0x0080 }, /* R1815 (0x717) - AIF1TX3MIX Input 4 Volume */ + { 0x00000718, 0x0000 }, /* R1816 (0x718) - AIF1TX4MIX Input 1 Source */ + { 0x00000719, 0x0080 }, /* R1817 (0x719) - AIF1TX4MIX Input 1 Volume */ + { 0x0000071a, 0x0000 }, /* R1818 (0x71a) - AIF1TX4MIX Input 2 Source */ + { 0x0000071b, 0x0080 }, /* R1819 (0x71b) - AIF1TX4MIX Input 2 Volume */ + { 0x0000071c, 0x0000 }, /* R1820 (0x71c) - AIF1TX4MIX Input 3 Source */ + { 0x0000071d, 0x0080 }, /* R1821 (0x71d) - AIF1TX4MIX Input 3 Volume */ + { 0x0000071e, 0x0000 }, /* R1822 (0x71e) - AIF1TX4MIX Input 4 Source */ + { 0x0000071f, 0x0080 }, /* R1823 (0x71f) - AIF1TX4MIX Input 4 Volume */ + { 0x00000720, 0x0000 }, /* R1824 (0x720) - AIF1TX5MIX Input 1 Source */ + { 0x00000721, 0x0080 }, /* R1825 (0x721) - AIF1TX5MIX Input 1 Volume */ + { 0x00000722, 0x0000 }, /* R1826 (0x722) - AIF1TX5MIX Input 2 Source */ + { 0x00000723, 0x0080 }, /* R1827 (0x723) - AIF1TX5MIX Input 2 Volume */ + { 0x00000724, 0x0000 }, /* R1828 (0x724) - AIF1TX5MIX Input 3 Source */ + { 0x00000725, 0x0080 }, /* R1829 (0x725) - AIF1TX5MIX Input 3 Volume */ + { 0x00000726, 0x0000 }, /* R1830 (0x726) - AIF1TX5MIX Input 4 Source */ + { 0x00000727, 0x0080 }, /* R1831 (0x727) - AIF1TX5MIX Input 4 Volume */ + { 0x00000728, 0x0000 }, /* R1832 (0x728) - AIF1TX6MIX Input 1 Source */ + { 0x00000729, 0x0080 }, /* R1833 (0x729) - AIF1TX6MIX Input 1 Volume */ + { 0x0000072a, 0x0000 }, /* R1834 (0x72a) - AIF1TX6MIX Input 2 Source */ + { 0x0000072b, 0x0080 }, /* R1835 (0x72b) - AIF1TX6MIX Input 2 Volume */ + { 0x0000072c, 0x0000 }, /* R1836 (0x72c) - AIF1TX6MIX Input 3 Source */ + { 0x0000072d, 0x0080 }, /* R1837 (0x72d) - AIF1TX6MIX Input 3 Volume */ + { 0x0000072e, 0x0000 }, /* R1838 (0x72e) - AIF1TX6MIX Input 4 Source */ + { 0x0000072f, 0x0080 }, /* R1839 (0x72f) - AIF1TX6MIX Input 4 Volume */ + { 0x00000730, 0x0000 }, /* R1840 (0x730) - AIF1TX7MIX Input 1 Source */ + { 0x00000731, 0x0080 }, /* R1841 (0x731) - AIF1TX7MIX Input 1 Volume */ + { 0x00000732, 0x0000 }, /* R1842 (0x732) - AIF1TX7MIX Input 2 Source */ + { 0x00000733, 0x0080 }, /* R1843 (0x733) - AIF1TX7MIX Input 2 Volume */ + { 0x00000734, 0x0000 }, /* R1844 (0x734) - AIF1TX7MIX Input 3 Source */ + { 0x00000735, 0x0080 }, /* R1845 (0x735) - AIF1TX7MIX Input 3 Volume */ + { 0x00000736, 0x0000 }, /* R1846 (0x736) - AIF1TX7MIX Input 4 Source */ + { 0x00000737, 0x0080 }, /* R1847 (0x737) - AIF1TX7MIX Input 4 Volume */ + { 0x00000738, 0x0000 }, /* R1848 (0x738) - AIF1TX8MIX Input 1 Source */ + { 0x00000739, 0x0080 }, /* R1849 (0x739) - AIF1TX8MIX Input 1 Volume */ + { 0x0000073a, 0x0000 }, /* R1850 (0x73a) - AIF1TX8MIX Input 2 Source */ + { 0x0000073b, 0x0080 }, /* R1851 (0x73b) - AIF1TX8MIX Input 2 Volume */ + { 0x0000073c, 0x0000 }, /* R1852 (0x73c) - AIF1TX8MIX Input 3 Source */ + { 0x0000073d, 0x0080 }, /* R1853 (0x73d) - AIF1TX8MIX Input 3 Volume */ + { 0x0000073e, 0x0000 }, /* R1854 (0x73e) - AIF1TX8MIX Input 4 Source */ + { 0x0000073f, 0x0080 }, /* R1855 (0x73f) - AIF1TX8MIX Input 4 Volume */ + { 0x00000740, 0x0000 }, /* R1856 (0x740) - AIF2TX1MIX Input 1 Source */ + { 0x00000741, 0x0080 }, /* R1857 (0x741) - AIF2TX1MIX Input 1 Volume */ + { 0x00000742, 0x0000 }, /* R1858 (0x742) - AIF2TX1MIX Input 2 Source */ + { 0x00000743, 0x0080 }, /* R1859 (0x743) - AIF2TX1MIX Input 2 Volume */ + { 0x00000744, 0x0000 }, /* R1860 (0x744) - AIF2TX1MIX Input 3 Source */ + { 0x00000745, 0x0080 }, /* R1861 (0x745) - AIF2TX1MIX Input 3 Volume */ + { 0x00000746, 0x0000 }, /* R1862 (0x746) - AIF2TX1MIX Input 4 Source */ + { 0x00000747, 0x0080 }, /* R1863 (0x747) - AIF2TX1MIX Input 4 Volume */ + { 0x00000748, 0x0000 }, /* R1864 (0x748) - AIF2TX2MIX Input 1 Source */ + { 0x00000749, 0x0080 }, /* R1865 (0x749) - AIF2TX2MIX Input 1 Volume */ + { 0x0000074a, 0x0000 }, /* R1866 (0x74a) - AIF2TX2MIX Input 2 Source */ + { 0x0000074b, 0x0080 }, /* R1867 (0x74b) - AIF2TX2MIX Input 2 Volume */ + { 0x0000074c, 0x0000 }, /* R1868 (0x74c) - AIF2TX2MIX Input 3 Source */ + { 0x0000074d, 0x0080 }, /* R1869 (0x74d) - AIF2TX2MIX Input 3 Volume */ + { 0x0000074e, 0x0000 }, /* R1870 (0x74e) - AIF2TX2MIX Input 4 Source */ + { 0x0000074f, 0x0080 }, /* R1871 (0x74f) - AIF2TX2MIX Input 4 Volume */ + { 0x00000750, 0x0000 }, /* R1872 (0x750) - AIF2TX3MIX Input 1 Source */ + { 0x00000751, 0x0080 }, /* R1873 (0x751) - AIF2TX3MIX Input 1 Volume */ + { 0x00000752, 0x0000 }, /* R1874 (0x752) - AIF2TX3MIX Input 2 Source */ + { 0x00000753, 0x0080 }, /* R1875 (0x753) - AIF2TX3MIX Input 2 Volume */ + { 0x00000754, 0x0000 }, /* R1876 (0x754) - AIF2TX3MIX Input 3 Source */ + { 0x00000755, 0x0080 }, /* R1877 (0x755) - AIF2TX3MIX Input 3 Volume */ + { 0x00000756, 0x0000 }, /* R1878 (0x756) - AIF2TX3MIX Input 4 Source */ + { 0x00000757, 0x0080 }, /* R1879 (0x757) - AIF2TX3MIX Input 4 Volume */ + { 0x00000758, 0x0000 }, /* R1880 (0x758) - AIF2TX4MIX Input 1 Source */ + { 0x00000759, 0x0080 }, /* R1881 (0x759) - AIF2TX4MIX Input 1 Volume */ + { 0x0000075a, 0x0000 }, /* R1882 (0x75a) - AIF2TX4MIX Input 2 Source */ + { 0x0000075b, 0x0080 }, /* R1883 (0x75b) - AIF2TX4MIX Input 2 Volume */ + { 0x0000075c, 0x0000 }, /* R1884 (0x75c) - AIF2TX4MIX Input 3 Source */ + { 0x0000075d, 0x0080 }, /* R1885 (0x75d) - AIF2TX4MIX Input 3 Volume */ + { 0x0000075e, 0x0000 }, /* R1886 (0x75e) - AIF2TX4MIX Input 4 Source */ + { 0x0000075f, 0x0080 }, /* R1887 (0x75f) - AIF2TX4MIX Input 4 Volume */ + { 0x00000760, 0x0000 }, /* R1888 (0x760) - AIF2TX5MIX Input 1 Source */ + { 0x00000761, 0x0080 }, /* R1889 (0x761) - AIF2TX5MIX Input 1 Volume */ + { 0x00000762, 0x0000 }, /* R1890 (0x762) - AIF2TX5MIX Input 2 Source */ + { 0x00000763, 0x0080 }, /* R1891 (0x763) - AIF2TX5MIX Input 2 Volume */ + { 0x00000764, 0x0000 }, /* R1892 (0x764) - AIF2TX5MIX Input 3 Source */ + { 0x00000765, 0x0080 }, /* R1893 (0x765) - AIF2TX5MIX Input 3 Volume */ + { 0x00000766, 0x0000 }, /* R1894 (0x766) - AIF2TX5MIX Input 4 Source */ + { 0x00000767, 0x0080 }, /* R1895 (0x767) - AIF2TX5MIX Input 4 Volume */ + { 0x00000768, 0x0000 }, /* R1896 (0x768) - AIF2TX6MIX Input 1 Source */ + { 0x00000769, 0x0080 }, /* R1897 (0x769) - AIF2TX6MIX Input 1 Volume */ + { 0x0000076a, 0x0000 }, /* R1898 (0x76a) - AIF2TX6MIX Input 2 Source */ + { 0x0000076b, 0x0080 }, /* R1899 (0x76b) - AIF2TX6MIX Input 2 Volume */ + { 0x0000076c, 0x0000 }, /* R1900 (0x76c) - AIF2TX6MIX Input 3 Source */ + { 0x0000076d, 0x0080 }, /* R1901 (0x76d) - AIF2TX6MIX Input 3 Volume */ + { 0x0000076e, 0x0000 }, /* R1902 (0x76e) - AIF2TX6MIX Input 4 Source */ + { 0x0000076f, 0x0080 }, /* R1903 (0x76f) - AIF2TX6MIX Input 4 Volume */ + { 0x00000770, 0x0000 }, /* R1904 (0x770) - AIF2TX7MIX Input 1 Source */ + { 0x00000771, 0x0080 }, /* R1905 (0x771) - AIF2TX7MIX Input 1 Volume */ + { 0x00000772, 0x0000 }, /* R1906 (0x772) - AIF2TX7MIX Input 2 Source */ + { 0x00000773, 0x0080 }, /* R1907 (0x773) - AIF2TX7MIX Input 2 Volume */ + { 0x00000774, 0x0000 }, /* R1908 (0x774) - AIF2TX7MIX Input 3 Source */ + { 0x00000775, 0x0080 }, /* R1909 (0x775) - AIF2TX7MIX Input 3 Volume */ + { 0x00000776, 0x0000 }, /* R1910 (0x776) - AIF2TX7MIX Input 4 Source */ + { 0x00000777, 0x0080 }, /* R1911 (0x777) - AIF2TX7MIX Input 4 Volume */ + { 0x00000778, 0x0000 }, /* R1912 (0x778) - AIF2TX8MIX Input 1 Source */ + { 0x00000779, 0x0080 }, /* R1913 (0x779) - AIF2TX8MIX Input 1 Volume */ + { 0x0000077a, 0x0000 }, /* R1914 (0x77a) - AIF2TX8MIX Input 2 Source */ + { 0x0000077b, 0x0080 }, /* R1915 (0x77b) - AIF2TX8MIX Input 2 Volume */ + { 0x0000077c, 0x0000 }, /* R1916 (0x77c) - AIF2TX8MIX Input 3 Source */ + { 0x0000077d, 0x0080 }, /* R1917 (0x77d) - AIF2TX8MIX Input 3 Volume */ + { 0x0000077e, 0x0000 }, /* R1918 (0x77e) - AIF2TX8MIX Input 4 Source */ + { 0x0000077f, 0x0080 }, /* R1919 (0x77f) - AIF2TX8MIX Input 4 Volume */ + { 0x00000780, 0x0000 }, /* R1920 (0x780) - AIF3TX1MIX Input 1 Source */ + { 0x00000781, 0x0080 }, /* R1921 (0x781) - AIF3TX1MIX Input 1 Volume */ + { 0x00000782, 0x0000 }, /* R1922 (0x782) - AIF3TX1MIX Input 2 Source */ + { 0x00000783, 0x0080 }, /* R1923 (0x783) - AIF3TX1MIX Input 2 Volume */ + { 0x00000784, 0x0000 }, /* R1924 (0x784) - AIF3TX1MIX Input 3 Source */ + { 0x00000785, 0x0080 }, /* R1925 (0x785) - AIF3TX1MIX Input 3 Volume */ + { 0x00000786, 0x0000 }, /* R1926 (0x786) - AIF3TX1MIX Input 4 Source */ + { 0x00000787, 0x0080 }, /* R1927 (0x787) - AIF3TX1MIX Input 4 Volume */ + { 0x00000788, 0x0000 }, /* R1928 (0x788) - AIF3TX2MIX Input 1 Source */ + { 0x00000789, 0x0080 }, /* R1929 (0x789) - AIF3TX2MIX Input 1 Volume */ + { 0x0000078a, 0x0000 }, /* R1930 (0x78a) - AIF3TX2MIX Input 2 Source */ + { 0x0000078b, 0x0080 }, /* R1931 (0x78b) - AIF3TX2MIX Input 2 Volume */ + { 0x0000078c, 0x0000 }, /* R1932 (0x78c) - AIF3TX2MIX Input 3 Source */ + { 0x0000078d, 0x0080 }, /* R1933 (0x78d) - AIF3TX2MIX Input 3 Volume */ + { 0x0000078e, 0x0000 }, /* R1934 (0x78e) - AIF3TX2MIX Input 4 Source */ + { 0x0000078f, 0x0080 }, /* R1935 (0x78f) - AIF3TX2MIX Input 4 Volume */ + { 0x000007a0, 0x0000 }, /* R1952 (0x7a0) - AIF4TX1MIX Input 1 Source */ + { 0x000007a1, 0x0080 }, /* R1953 (0x7a1) - AIF4TX1MIX Input 1 Volume */ + { 0x000007a2, 0x0000 }, /* R1954 (0x7a2) - AIF4TX1MIX Input 2 Source */ + { 0x000007a3, 0x0080 }, /* R1955 (0x7a3) - AIF4TX1MIX Input 2 Volume */ + { 0x000007a4, 0x0000 }, /* R1956 (0x7a4) - AIF4TX1MIX Input 3 Source */ + { 0x000007a5, 0x0080 }, /* R1957 (0x7a5) - AIF4TX1MIX Input 3 Volume */ + { 0x000007a6, 0x0000 }, /* R1958 (0x7a6) - AIF4TX1MIX Input 4 Source */ + { 0x000007a7, 0x0080 }, /* R1959 (0x7a7) - AIF4TX1MIX Input 4 Volume */ + { 0x000007a8, 0x0000 }, /* R1960 (0x7a8) - AIF4TX2MIX Input 1 Source */ + { 0x000007a9, 0x0080 }, /* R1961 (0x7a9) - AIF4TX2MIX Input 1 Volume */ + { 0x000007aa, 0x0000 }, /* R1962 (0x7aa) - AIF4TX2MIX Input 2 Source */ + { 0x000007ab, 0x0080 }, /* R1963 (0x7ab) - AIF4TX2MIX Input 2 Volume */ + { 0x000007ac, 0x0000 }, /* R1964 (0x7ac) - AIF4TX2MIX Input 3 Source */ + { 0x000007ad, 0x0080 }, /* R1965 (0x7ad) - AIF4TX2MIX Input 3 Volume */ + { 0x000007ae, 0x0000 }, /* R1966 (0x7ae) - AIF4TX2MIX Input 4 Source */ + { 0x000007af, 0x0080 }, /* R1967 (0x7af) - AIF4TX2MIX Input 4 Volume */ + { 0x000007c0, 0x0000 }, /* R1984 (0x7c0) - SLIMTX1MIX Input 1 Source */ + { 0x000007c1, 0x0080 }, /* R1985 (0x7c1) - SLIMTX1MIX Input 1 Volume */ + { 0x000007c2, 0x0000 }, /* R1986 (0x7c2) - SLIMTX1MIX Input 2 Source */ + { 0x000007c3, 0x0080 }, /* R1987 (0x7c3) - SLIMTX1MIX Input 2 Volume */ + { 0x000007c4, 0x0000 }, /* R1988 (0x7c4) - SLIMTX1MIX Input 3 Source */ + { 0x000007c5, 0x0080 }, /* R1989 (0x7c5) - SLIMTX1MIX Input 3 Volume */ + { 0x000007c6, 0x0000 }, /* R1990 (0x7c6) - SLIMTX1MIX Input 4 Source */ + { 0x000007c7, 0x0080 }, /* R1991 (0x7c7) - SLIMTX1MIX Input 4 Volume */ + { 0x000007c8, 0x0000 }, /* R1992 (0x7c8) - SLIMTX2MIX Input 1 Source */ + { 0x000007c9, 0x0080 }, /* R1993 (0x7c9) - SLIMTX2MIX Input 1 Volume */ + { 0x000007ca, 0x0000 }, /* R1994 (0x7ca) - SLIMTX2MIX Input 2 Source */ + { 0x000007cb, 0x0080 }, /* R1995 (0x7cb) - SLIMTX2MIX Input 2 Volume */ + { 0x000007cc, 0x0000 }, /* R1996 (0x7cc) - SLIMTX2MIX Input 3 Source */ + { 0x000007cd, 0x0080 }, /* R1997 (0x7cd) - SLIMTX2MIX Input 3 Volume */ + { 0x000007ce, 0x0000 }, /* R1998 (0x7ce) - SLIMTX2MIX Input 4 Source */ + { 0x000007cf, 0x0080 }, /* R1999 (0x7cf) - SLIMTX2MIX Input 4 Volume */ + { 0x000007d0, 0x0000 }, /* R2000 (0x7d0) - SLIMTX3MIX Input 1 Source */ + { 0x000007d1, 0x0080 }, /* R2001 (0x7d1) - SLIMTX3MIX Input 1 Volume */ + { 0x000007d2, 0x0000 }, /* R2002 (0x7d2) - SLIMTX3MIX Input 2 Source */ + { 0x000007d3, 0x0080 }, /* R2003 (0x7d3) - SLIMTX3MIX Input 2 Volume */ + { 0x000007d4, 0x0000 }, /* R2004 (0x7d4) - SLIMTX3MIX Input 3 Source */ + { 0x000007d5, 0x0080 }, /* R2005 (0x7d5) - SLIMTX3MIX Input 3 Volume */ + { 0x000007d6, 0x0000 }, /* R2006 (0x7d6) - SLIMTX3MIX Input 4 Source */ + { 0x000007d7, 0x0080 }, /* R2007 (0x7d7) - SLIMTX3MIX Input 4 Volume */ + { 0x000007d8, 0x0000 }, /* R2008 (0x7d8) - SLIMTX4MIX Input 1 Source */ + { 0x000007d9, 0x0080 }, /* R2009 (0x7d9) - SLIMTX4MIX Input 1 Volume */ + { 0x000007da, 0x0000 }, /* R2010 (0x7da) - SLIMTX4MIX Input 2 Source */ + { 0x000007db, 0x0080 }, /* R2011 (0x7db) - SLIMTX4MIX Input 2 Volume */ + { 0x000007dc, 0x0000 }, /* R2012 (0x7dc) - SLIMTX4MIX Input 3 Source */ + { 0x000007dd, 0x0080 }, /* R2013 (0x7dd) - SLIMTX4MIX Input 3 Volume */ + { 0x000007de, 0x0000 }, /* R2014 (0x7de) - SLIMTX4MIX Input 4 Source */ + { 0x000007df, 0x0080 }, /* R2015 (0x7df) - SLIMTX4MIX Input 4 Volume */ + { 0x000007e0, 0x0000 }, /* R2016 (0x7e0) - SLIMTX5MIX Input 1 Source */ + { 0x000007e1, 0x0080 }, /* R2017 (0x7e1) - SLIMTX5MIX Input 1 Volume */ + { 0x000007e2, 0x0000 }, /* R2018 (0x7e2) - SLIMTX5MIX Input 2 Source */ + { 0x000007e3, 0x0080 }, /* R2019 (0x7e3) - SLIMTX5MIX Input 2 Volume */ + { 0x000007e4, 0x0000 }, /* R2020 (0x7e4) - SLIMTX5MIX Input 3 Source */ + { 0x000007e5, 0x0080 }, /* R2021 (0x7e5) - SLIMTX5MIX Input 3 Volume */ + { 0x000007e6, 0x0000 }, /* R2022 (0x7e6) - SLIMTX5MIX Input 4 Source */ + { 0x000007e7, 0x0080 }, /* R2023 (0x7e7) - SLIMTX5MIX Input 4 Volume */ + { 0x000007e8, 0x0000 }, /* R2024 (0x7e8) - SLIMTX6MIX Input 1 Source */ + { 0x000007e9, 0x0080 }, /* R2025 (0x7e9) - SLIMTX6MIX Input 1 Volume */ + { 0x000007ea, 0x0000 }, /* R2026 (0x7ea) - SLIMTX6MIX Input 2 Source */ + { 0x000007eb, 0x0080 }, /* R2027 (0x7eb) - SLIMTX6MIX Input 2 Volume */ + { 0x000007ec, 0x0000 }, /* R2028 (0x7ec) - SLIMTX6MIX Input 3 Source */ + { 0x000007ed, 0x0080 }, /* R2029 (0x7ed) - SLIMTX6MIX Input 3 Volume */ + { 0x000007ee, 0x0000 }, /* R2030 (0x7ee) - SLIMTX6MIX Input 4 Source */ + { 0x000007ef, 0x0080 }, /* R2031 (0x7ef) - SLIMTX6MIX Input 4 Volume */ + { 0x000007f0, 0x0000 }, /* R2032 (0x7f0) - SLIMTX7MIX Input 1 Source */ + { 0x000007f1, 0x0080 }, /* R2033 (0x7f1) - SLIMTX7MIX Input 1 Volume */ + { 0x000007f2, 0x0000 }, /* R2034 (0x7f2) - SLIMTX7MIX Input 2 Source */ + { 0x000007f3, 0x0080 }, /* R2035 (0x7f3) - SLIMTX7MIX Input 2 Volume */ + { 0x000007f4, 0x0000 }, /* R2036 (0x7f4) - SLIMTX7MIX Input 3 Source */ + { 0x000007f5, 0x0080 }, /* R2037 (0x7f5) - SLIMTX7MIX Input 3 Volume */ + { 0x000007f6, 0x0000 }, /* R2038 (0x7f6) - SLIMTX7MIX Input 4 Source */ + { 0x000007f7, 0x0080 }, /* R2039 (0x7f7) - SLIMTX7MIX Input 4 Volume */ + { 0x000007f8, 0x0000 }, /* R2040 (0x7f8) - SLIMTX8MIX Input 1 Source */ + { 0x000007f9, 0x0080 }, /* R2041 (0x7f9) - SLIMTX8MIX Input 1 Volume */ + { 0x000007fa, 0x0000 }, /* R2042 (0x7fa) - SLIMTX8MIX Input 2 Source */ + { 0x000007fb, 0x0080 }, /* R2043 (0x7fb) - SLIMTX8MIX Input 2 Volume */ + { 0x000007fc, 0x0000 }, /* R2044 (0x7fc) - SLIMTX8MIX Input 3 Source */ + { 0x000007fd, 0x0080 }, /* R2045 (0x7fd) - SLIMTX8MIX Input 3 Volume */ + { 0x000007fe, 0x0000 }, /* R2046 (0x7fe) - SLIMTX8MIX Input 4 Source */ + { 0x000007ff, 0x0080 }, /* R2047 (0x7ff) - SLIMTX8MIX Input 4 Volume */ + { 0x00000800, 0x0000 }, /* R2048 (0x800) - SPDIF1TX1MIX Input 1 Source */ + { 0x00000801, 0x0080 }, /* R2049 (0x801) - SPDIF1TX1MIX Input 1 Volume */ + { 0x00000808, 0x0000 }, /* R2056 (0x808) - SPDIF1TX2MIX Input 1 Source */ + { 0x00000809, 0x0080 }, /* R2057 (0x809) - SPDIF1TX2MIX Input 1 Volume */ + { 0x00000880, 0x0000 }, /* R2176 (0x880) - EQ1MIX Input 1 Source */ + { 0x00000881, 0x0080 }, /* R2177 (0x881) - EQ1MIX Input 1 Volume */ + { 0x00000882, 0x0000 }, /* R2178 (0x882) - EQ1MIX Input 2 Source */ + { 0x00000883, 0x0080 }, /* R2179 (0x883) - EQ1MIX Input 2 Volume */ + { 0x00000884, 0x0000 }, /* R2180 (0x884) - EQ1MIX Input 3 Source */ + { 0x00000885, 0x0080 }, /* R2181 (0x885) - EQ1MIX Input 3 Volume */ + { 0x00000886, 0x0000 }, /* R2182 (0x886) - EQ1MIX Input 4 Source */ + { 0x00000887, 0x0080 }, /* R2183 (0x887) - EQ1MIX Input 4 Volume */ + { 0x00000888, 0x0000 }, /* R2184 (0x888) - EQ2MIX Input 1 Source */ + { 0x00000889, 0x0080 }, /* R2185 (0x889) - EQ2MIX Input 1 Volume */ + { 0x0000088a, 0x0000 }, /* R2186 (0x88a) - EQ2MIX Input 2 Source */ + { 0x0000088b, 0x0080 }, /* R2187 (0x88b) - EQ2MIX Input 2 Volume */ + { 0x0000088c, 0x0000 }, /* R2188 (0x88c) - EQ2MIX Input 3 Source */ + { 0x0000088d, 0x0080 }, /* R2189 (0x88d) - EQ2MIX Input 3 Volume */ + { 0x0000088e, 0x0000 }, /* R2190 (0x88e) - EQ2MIX Input 4 Source */ + { 0x0000088f, 0x0080 }, /* R2191 (0x88f) - EQ2MIX Input 4 Volume */ + { 0x00000890, 0x0000 }, /* R2192 (0x890) - EQ3MIX Input 1 Source */ + { 0x00000891, 0x0080 }, /* R2193 (0x891) - EQ3MIX Input 1 Volume */ + { 0x00000892, 0x0000 }, /* R2194 (0x892) - EQ3MIX Input 2 Source */ + { 0x00000893, 0x0080 }, /* R2195 (0x893) - EQ3MIX Input 2 Volume */ + { 0x00000894, 0x0000 }, /* R2196 (0x894) - EQ3MIX Input 3 Source */ + { 0x00000895, 0x0080 }, /* R2197 (0x895) - EQ3MIX Input 3 Volume */ + { 0x00000896, 0x0000 }, /* R2198 (0x896) - EQ3MIX Input 4 Source */ + { 0x00000897, 0x0080 }, /* R2199 (0x897) - EQ3MIX Input 4 Volume */ + { 0x00000898, 0x0000 }, /* R2200 (0x898) - EQ4MIX Input 1 Source */ + { 0x00000899, 0x0080 }, /* R2201 (0x899) - EQ4MIX Input 1 Volume */ + { 0x0000089a, 0x0000 }, /* R2202 (0x89a) - EQ4MIX Input 2 Source */ + { 0x0000089b, 0x0080 }, /* R2203 (0x89b) - EQ4MIX Input 2 Volume */ + { 0x0000089c, 0x0000 }, /* R2204 (0x89c) - EQ4MIX Input 3 Source */ + { 0x0000089d, 0x0080 }, /* R2205 (0x89d) - EQ4MIX Input 3 Volume */ + { 0x0000089e, 0x0000 }, /* R2206 (0x89e) - EQ4MIX Input 4 Source */ + { 0x0000089f, 0x0080 }, /* R2207 (0x89f) - EQ4MIX Input 4 Volume */ + { 0x000008c0, 0x0000 }, /* R2240 (0x8c0) - DRC1LMIX Input 1 Source */ + { 0x000008c1, 0x0080 }, /* R2241 (0x8c1) - DRC1LMIX Input 1 Volume */ + { 0x000008c2, 0x0000 }, /* R2242 (0x8c2) - DRC1LMIX Input 2 Source */ + { 0x000008c3, 0x0080 }, /* R2243 (0x8c3) - DRC1LMIX Input 2 Volume */ + { 0x000008c4, 0x0000 }, /* R2244 (0x8c4) - DRC1LMIX Input 3 Source */ + { 0x000008c5, 0x0080 }, /* R2245 (0x8c5) - DRC1LMIX Input 3 Volume */ + { 0x000008c6, 0x0000 }, /* R2246 (0x8c6) - DRC1LMIX Input 4 Source */ + { 0x000008c7, 0x0080 }, /* R2247 (0x8c7) - DRC1LMIX Input 4 Volume */ + { 0x000008c8, 0x0000 }, /* R2248 (0x8c8) - DRC1RMIX Input 1 Source */ + { 0x000008c9, 0x0080 }, /* R2249 (0x8c9) - DRC1RMIX Input 1 Volume */ + { 0x000008ca, 0x0000 }, /* R2250 (0x8ca) - DRC1RMIX Input 2 Source */ + { 0x000008cb, 0x0080 }, /* R2251 (0x8cb) - DRC1RMIX Input 2 Volume */ + { 0x000008cc, 0x0000 }, /* R2252 (0x8cc) - DRC1RMIX Input 3 Source */ + { 0x000008cd, 0x0080 }, /* R2253 (0x8cd) - DRC1RMIX Input 3 Volume */ + { 0x000008ce, 0x0000 }, /* R2254 (0x8ce) - DRC1RMIX Input 4 Source */ + { 0x000008cf, 0x0080 }, /* R2255 (0x8cf) - DRC1RMIX Input 4 Volume */ + { 0x000008d0, 0x0000 }, /* R2256 (0x8d0) - DRC2LMIX Input 1 Source */ + { 0x000008d1, 0x0080 }, /* R2257 (0x8d1) - DRC2LMIX Input 1 Volume */ + { 0x000008d2, 0x0000 }, /* R2258 (0x8d2) - DRC2LMIX Input 2 Source */ + { 0x000008d3, 0x0080 }, /* R2259 (0x8d3) - DRC2LMIX Input 2 Volume */ + { 0x000008d4, 0x0000 }, /* R2260 (0x8d4) - DRC2LMIX Input 3 Source */ + { 0x000008d5, 0x0080 }, /* R2261 (0x8d5) - DRC2LMIX Input 3 Volume */ + { 0x000008d6, 0x0000 }, /* R2262 (0x8d6) - DRC2LMIX Input 4 Source */ + { 0x000008d7, 0x0080 }, /* R2263 (0x8d7) - DRC2LMIX Input 4 Volume */ + { 0x000008d8, 0x0000 }, /* R2264 (0x8d8) - DRC2RMIX Input 1 Source */ + { 0x000008d9, 0x0080 }, /* R2265 (0x8d9) - DRC2RMIX Input 1 Volume */ + { 0x000008da, 0x0000 }, /* R2266 (0x8da) - DRC2RMIX Input 2 Source */ + { 0x000008db, 0x0080 }, /* R2267 (0x8db) - DRC2RMIX Input 2 Volume */ + { 0x000008dc, 0x0000 }, /* R2268 (0x8dc) - DRC2RMIX Input 3 Source */ + { 0x000008dd, 0x0080 }, /* R2269 (0x8dd) - DRC2RMIX Input 3 Volume */ + { 0x000008de, 0x0000 }, /* R2270 (0x8de) - DRC2RMIX Input 4 Source */ + { 0x000008df, 0x0080 }, /* R2271 (0x8df) - DRC2RMIX Input 4 Volume */ + { 0x00000900, 0x0000 }, /* R2304 (0x900) - HPLP1MIX Input 1 Source */ + { 0x00000901, 0x0080 }, /* R2305 (0x901) - HPLP1MIX Input 1 Volume */ + { 0x00000902, 0x0000 }, /* R2306 (0x902) - HPLP1MIX Input 2 Source */ + { 0x00000903, 0x0080 }, /* R2307 (0x903) - HPLP1MIX Input 2 Volume */ + { 0x00000904, 0x0000 }, /* R2308 (0x904) - HPLP1MIX Input 3 Source */ + { 0x00000905, 0x0080 }, /* R2309 (0x905) - HPLP1MIX Input 3 Volume */ + { 0x00000906, 0x0000 }, /* R2310 (0x906) - HPLP1MIX Input 4 Source */ + { 0x00000907, 0x0080 }, /* R2311 (0x907) - HPLP1MIX Input 4 Volume */ + { 0x00000908, 0x0000 }, /* R2312 (0x908) - HPLP2MIX Input 1 Source */ + { 0x00000909, 0x0080 }, /* R2313 (0x909) - HPLP2MIX Input 1 Volume */ + { 0x0000090a, 0x0000 }, /* R2314 (0x90a) - HPLP2MIX Input 2 Source */ + { 0x0000090b, 0x0080 }, /* R2315 (0x90b) - HPLP2MIX Input 2 Volume */ + { 0x0000090c, 0x0000 }, /* R2316 (0x90c) - HPLP2MIX Input 3 Source */ + { 0x0000090d, 0x0080 }, /* R2317 (0x90d) - HPLP2MIX Input 3 Volume */ + { 0x0000090e, 0x0000 }, /* R2318 (0x90e) - HPLP2MIX Input 4 Source */ + { 0x0000090f, 0x0080 }, /* R2319 (0x90f) - HPLP2MIX Input 4 Volume */ + { 0x00000910, 0x0000 }, /* R2320 (0x910) - HPLP3MIX Input 1 Source */ + { 0x00000911, 0x0080 }, /* R2321 (0x911) - HPLP3MIX Input 1 Volume */ + { 0x00000912, 0x0000 }, /* R2322 (0x912) - HPLP3MIX Input 2 Source */ + { 0x00000913, 0x0080 }, /* R2323 (0x913) - HPLP3MIX Input 2 Volume */ + { 0x00000914, 0x0000 }, /* R2324 (0x914) - HPLP3MIX Input 3 Source */ + { 0x00000915, 0x0080 }, /* R2325 (0x915) - HPLP3MIX Input 3 Volume */ + { 0x00000916, 0x0000 }, /* R2326 (0x916) - HPLP3MIX Input 4 Source */ + { 0x00000917, 0x0080 }, /* R2327 (0x917) - HPLP3MIX Input 4 Volume */ + { 0x00000918, 0x0000 }, /* R2328 (0x918) - HPLP4MIX Input 1 Source */ + { 0x00000919, 0x0080 }, /* R2329 (0x919) - HPLP4MIX Input 1 Volume */ + { 0x0000091a, 0x0000 }, /* R2330 (0x91a) - HPLP4MIX Input 2 Source */ + { 0x0000091b, 0x0080 }, /* R2331 (0x91b) - HPLP4MIX Input 2 Volume */ + { 0x0000091c, 0x0000 }, /* R2332 (0x91c) - HPLP4MIX Input 3 Source */ + { 0x0000091d, 0x0080 }, /* R2333 (0x91d) - HPLP4MIX Input 3 Volume */ + { 0x0000091e, 0x0000 }, /* R2334 (0x91e) - HPLP4MIX Input 4 Source */ + { 0x0000091f, 0x0080 }, /* R2335 (0x91f) - HPLP4MIX Input 4 Volume */ + { 0x00000940, 0x0000 }, /* R2368 (0x940) - DSP1LMIX Input 1 Source */ + { 0x00000941, 0x0080 }, /* R2369 (0x941) - DSP1LMIX Input 1 Volume */ + { 0x00000942, 0x0000 }, /* R2370 (0x942) - DSP1LMIX Input 2 Source */ + { 0x00000943, 0x0080 }, /* R2371 (0x943) - DSP1LMIX Input 2 Volume */ + { 0x00000944, 0x0000 }, /* R2372 (0x944) - DSP1LMIX Input 3 Source */ + { 0x00000945, 0x0080 }, /* R2373 (0x945) - DSP1LMIX Input 3 Volume */ + { 0x00000946, 0x0000 }, /* R2374 (0x946) - DSP1LMIX Input 4 Source */ + { 0x00000947, 0x0080 }, /* R2375 (0x947) - DSP1LMIX Input 4 Volume */ + { 0x00000948, 0x0000 }, /* R2376 (0x948) - DSP1RMIX Input 1 Source */ + { 0x00000949, 0x0080 }, /* R2377 (0x949) - DSP1RMIX Input 1 Volume */ + { 0x0000094a, 0x0000 }, /* R2378 (0x94a) - DSP1RMIX Input 2 Source */ + { 0x0000094b, 0x0080 }, /* R2379 (0x94b) - DSP1RMIX Input 2 Volume */ + { 0x0000094c, 0x0000 }, /* R2380 (0x94c) - DSP1RMIX Input 3 Source */ + { 0x0000094d, 0x0080 }, /* R2381 (0x94d) - DSP1RMIX Input 3 Volume */ + { 0x0000094e, 0x0000 }, /* R2382 (0x94e) - DSP1RMIX Input 4 Source */ + { 0x0000094f, 0x0080 }, /* R2383 (0x94f) - DSP1RMIX Input 4 Volume */ + { 0x00000950, 0x0000 }, /* R2384 (0x950) - DSP1AUX1MIX Input 1 Source */ + { 0x00000958, 0x0000 }, /* R2392 (0x958) - DSP1AUX2MIX Input 1 Source */ + { 0x00000960, 0x0000 }, /* R2400 (0x960) - DSP1AUX3MIX Input 1 Source */ + { 0x00000968, 0x0000 }, /* R2408 (0x968) - DSP1AUX4MIX Input 1 Source */ + { 0x00000970, 0x0000 }, /* R2416 (0x970) - DSP1AUX5MIX Input 1 Source */ + { 0x00000978, 0x0000 }, /* R2424 (0x978) - DSP1AUX6MIX Input 1 Source */ + { 0x00000980, 0x0000 }, /* R2432 (0x980) - DSP2LMIX Input 1 Source */ + { 0x00000981, 0x0080 }, /* R2433 (0x981) - DSP2LMIX Input 1 Volume */ + { 0x00000982, 0x0000 }, /* R2434 (0x982) - DSP2LMIX Input 2 Source */ + { 0x00000983, 0x0080 }, /* R2435 (0x983) - DSP2LMIX Input 2 Volume */ + { 0x00000984, 0x0000 }, /* R2436 (0x984) - DSP2LMIX Input 3 Source */ + { 0x00000985, 0x0080 }, /* R2437 (0x985) - DSP2LMIX Input 3 Volume */ + { 0x00000986, 0x0000 }, /* R2438 (0x986) - DSP2LMIX Input 4 Source */ + { 0x00000987, 0x0080 }, /* R2439 (0x987) - DSP2LMIX Input 4 Volume */ + { 0x00000988, 0x0000 }, /* R2440 (0x988) - DSP2RMIX Input 1 Source */ + { 0x00000989, 0x0080 }, /* R2441 (0x989) - DSP2RMIX Input 1 Volume */ + { 0x0000098a, 0x0000 }, /* R2442 (0x98a) - DSP2RMIX Input 2 Source */ + { 0x0000098b, 0x0080 }, /* R2443 (0x98b) - DSP2RMIX Input 2 Volume */ + { 0x0000098c, 0x0000 }, /* R2444 (0x98c) - DSP2RMIX Input 3 Source */ + { 0x0000098d, 0x0080 }, /* R2445 (0x98d) - DSP2RMIX Input 3 Volume */ + { 0x0000098e, 0x0000 }, /* R2446 (0x98e) - DSP2RMIX Input 4 Source */ + { 0x0000098f, 0x0080 }, /* R2447 (0x98f) - DSP2RMIX Input 4 Volume */ + { 0x00000990, 0x0000 }, /* R2448 (0x990) - DSP2AUX1MIX Input 1 Source */ + { 0x00000998, 0x0000 }, /* R2456 (0x998) - DSP2AUX2MIX Input 1 Source */ + { 0x000009a0, 0x0000 }, /* R2464 (0x9a0) - DSP2AUX3MIX Input 1 Source */ + { 0x000009a8, 0x0000 }, /* R2472 (0x9a8) - DSP2AUX4MIX Input 1 Source */ + { 0x000009b0, 0x0000 }, /* R2480 (0x9b0) - DSP2AUX5MIX Input 1 Source */ + { 0x000009b8, 0x0000 }, /* R2488 (0x9b8) - DSP2AUX6MIX Input 1 Source */ + { 0x000009c0, 0x0000 }, /* R2496 (0x9c0) - DSP3LMIX Input 1 Source */ + { 0x000009c1, 0x0080 }, /* R2497 (0x9c1) - DSP3LMIX Input 1 Volume */ + { 0x000009c2, 0x0000 }, /* R2498 (0x9c2) - DSP3LMIX Input 2 Source */ + { 0x000009c3, 0x0080 }, /* R2499 (0x9c3) - DSP3LMIX Input 2 Volume */ + { 0x000009c4, 0x0000 }, /* R2500 (0x9c4) - DSP3LMIX Input 3 Source */ + { 0x000009c5, 0x0080 }, /* R2501 (0x9c5) - DSP3LMIX Input 3 Volume */ + { 0x000009c6, 0x0000 }, /* R2502 (0x9c6) - DSP3LMIX Input 4 Source */ + { 0x000009c7, 0x0080 }, /* R2503 (0x9c7) - DSP3LMIX Input 4 Volume */ + { 0x000009c8, 0x0000 }, /* R2504 (0x9c8) - DSP3RMIX Input 1 Source */ + { 0x000009c9, 0x0080 }, /* R2505 (0x9c9) - DSP3RMIX Input 1 Volume */ + { 0x000009ca, 0x0000 }, /* R2506 (0x9ca) - DSP3RMIX Input 2 Source */ + { 0x000009cb, 0x0080 }, /* R2507 (0x9cb) - DSP3RMIX Input 2 Volume */ + { 0x000009cc, 0x0000 }, /* R2508 (0x9cc) - DSP3RMIX Input 3 Source */ + { 0x000009cd, 0x0080 }, /* R2509 (0x9cd) - DSP3RMIX Input 3 Volume */ + { 0x000009ce, 0x0000 }, /* R2510 (0x9ce) - DSP3RMIX Input 4 Source */ + { 0x000009cf, 0x0080 }, /* R2511 (0x9cf) - DSP3RMIX Input 4 Volume */ + { 0x000009d0, 0x0000 }, /* R2512 (0x9d0) - DSP3AUX1MIX Input 1 Source */ + { 0x000009d8, 0x0000 }, /* R2520 (0x9d8) - DSP3AUX2MIX Input 1 Source */ + { 0x000009e0, 0x0000 }, /* R2528 (0x9e0) - DSP3AUX3MIX Input 1 Source */ + { 0x000009e8, 0x0000 }, /* R2536 (0x9e8) - DSP3AUX4MIX Input 1 Source */ + { 0x000009f0, 0x0000 }, /* R2544 (0x9f0) - DSP3AUX5MIX Input 1 Source */ + { 0x000009f8, 0x0000 }, /* R2552 (0x9f8) - DSP3AUX6MIX Input 1 Source */ + { 0x00000a00, 0x0000 }, /* R2560 (0xa00) - DSP4LMIX Input 1 Source */ + { 0x00000a01, 0x0080 }, /* R2561 (0xa01) - DSP4LMIX Input 1 Volume */ + { 0x00000a02, 0x0000 }, /* R2562 (0xa02) - DSP4LMIX Input 2 Source */ + { 0x00000a03, 0x0080 }, /* R2563 (0xa03) - DSP4LMIX Input 2 Volume */ + { 0x00000a04, 0x0000 }, /* R2564 (0xa04) - DSP4LMIX Input 3 Source */ + { 0x00000a05, 0x0080 }, /* R2565 (0xa05) - DSP4LMIX Input 3 Volume */ + { 0x00000a06, 0x0000 }, /* R2566 (0xa06) - DSP4LMIX Input 4 Source */ + { 0x00000a07, 0x0080 }, /* R2567 (0xa07) - DSP4LMIX Input 4 Volume */ + { 0x00000a08, 0x0000 }, /* R2568 (0xa08) - DSP4RMIX Input 1 Source */ + { 0x00000a09, 0x0080 }, /* R2569 (0xa09) - DSP4RMIX Input 1 Volume */ + { 0x00000a0a, 0x0000 }, /* R2570 (0xa0a) - DSP4RMIX Input 2 Source */ + { 0x00000a0b, 0x0080 }, /* R2571 (0xa0b) - DSP4RMIX Input 2 Volume */ + { 0x00000a0c, 0x0000 }, /* R2572 (0xa0c) - DSP4RMIX Input 3 Source */ + { 0x00000a0d, 0x0080 }, /* R2573 (0xa0d) - DSP4RMIX Input 3 Volume */ + { 0x00000a0e, 0x0000 }, /* R2574 (0xa0e) - DSP4RMIX Input 4 Source */ + { 0x00000a0f, 0x0080 }, /* R2575 (0xa0f) - DSP4RMIX Input 4 Volume */ + { 0x00000a10, 0x0000 }, /* R2576 (0xa10) - DSP4AUX1MIX Input 1 Source */ + { 0x00000a18, 0x0000 }, /* R2584 (0xa18) - DSP4AUX2MIX Input 1 Source */ + { 0x00000a20, 0x0000 }, /* R2592 (0xa20) - DSP4AUX3MIX Input 1 Source */ + { 0x00000a28, 0x0000 }, /* R2600 (0xa28) - DSP4AUX4MIX Input 1 Source */ + { 0x00000a30, 0x0000 }, /* R2608 (0xa30) - DSP4AUX5MIX Input 1 Source */ + { 0x00000a38, 0x0000 }, /* R2616 (0xa38) - DSP4AUX6MIX Input 1 Source */ + { 0x00000a40, 0x0000 }, /* R2624 (0xa40) - DSP5LMIX Input 1 Source */ + { 0x00000a41, 0x0080 }, /* R2625 (0xa41) - DSP5LMIX Input 1 Volume */ + { 0x00000a42, 0x0000 }, /* R2626 (0xa42) - DSP5LMIX Input 2 Source */ + { 0x00000a43, 0x0080 }, /* R2627 (0xa43) - DSP5LMIX Input 2 Volume */ + { 0x00000a44, 0x0000 }, /* R2628 (0xa44) - DSP5LMIX Input 3 Source */ + { 0x00000a45, 0x0080 }, /* R2629 (0xa45) - DSP5LMIX Input 3 Volume */ + { 0x00000a46, 0x0000 }, /* R2630 (0xa46) - DSP5LMIX Input 4 Source */ + { 0x00000a47, 0x0080 }, /* R2631 (0xa47) - DSP5LMIX Input 4 Volume */ + { 0x00000a48, 0x0000 }, /* R2632 (0xa48) - DSP5RMIX Input 1 Source */ + { 0x00000a49, 0x0080 }, /* R2633 (0xa49) - DSP5RMIX Input 1 Volume */ + { 0x00000a4a, 0x0000 }, /* R2634 (0xa4a) - DSP5RMIX Input 2 Source */ + { 0x00000a4b, 0x0080 }, /* R2635 (0xa4b) - DSP5RMIX Input 2 Volume */ + { 0x00000a4c, 0x0000 }, /* R2636 (0xa4c) - DSP5RMIX Input 3 Source */ + { 0x00000a4d, 0x0080 }, /* R2637 (0xa4d) - DSP5RMIX Input 3 Volume */ + { 0x00000a4e, 0x0000 }, /* R2638 (0xa4e) - DSP5RMIX Input 4 Source */ + { 0x00000a4f, 0x0080 }, /* R2639 (0xa4f) - DSP5RMIX Input 4 Volume */ + { 0x00000a50, 0x0000 }, /* R2640 (0xa50) - DSP5AUX1MIX Input 1 Source */ + { 0x00000a58, 0x0000 }, /* R2658 (0xa58) - DSP5AUX2MIX Input 1 Source */ + { 0x00000a60, 0x0000 }, /* R2656 (0xa60) - DSP5AUX3MIX Input 1 Source */ + { 0x00000a68, 0x0000 }, /* R2664 (0xa68) - DSP5AUX4MIX Input 1 Source */ + { 0x00000a70, 0x0000 }, /* R2672 (0xa70) - DSP5AUX5MIX Input 1 Source */ + { 0x00000a78, 0x0000 }, /* R2680 (0xa78) - DSP5AUX6MIX Input 1 Source */ + { 0x00000a80, 0x0000 }, /* R2688 (0xa80) - ASRC1_1LMIX Input 1 Source */ + { 0x00000a88, 0x0000 }, /* R2696 (0xa88) - ASRC1_1RMIX Input 1 Source */ + { 0x00000a90, 0x0000 }, /* R2704 (0xa90) - ASRC1_2LMIX Input 1 Source */ + { 0x00000a98, 0x0000 }, /* R2712 (0xa98) - ASRC1_2RMIX Input 1 Source */ + { 0x00000aa0, 0x0000 }, /* R2720 (0xaa0) - ASRC2_1LMIX Input 1 Source */ + { 0x00000aa8, 0x0000 }, /* R2728 (0xaa8) - ASRC2_1RMIX Input 1 Source */ + { 0x00000ab0, 0x0000 }, /* R2736 (0xab0) - ASRC2_2LMIX Input 1 Source */ + { 0x00000ab8, 0x0000 }, /* R2744 (0xab8) - ASRC2_2RMIX Input 1 Source */ + { 0x00000b00, 0x0000 }, /* R2816 (0xb00) - ISRC1DEC1MIX Input 1 Source*/ + { 0x00000b08, 0x0000 }, /* R2824 (0xb08) - ISRC1DEC2MIX Input 1 Source*/ + { 0x00000b10, 0x0000 }, /* R2832 (0xb10) - ISRC1DEC3MIX Input 1 Source*/ + { 0x00000b18, 0x0000 }, /* R2840 (0xb18) - ISRC1DEC4MIX Input 1 Source*/ + { 0x00000b20, 0x0000 }, /* R2848 (0xb20) - ISRC1INT1MIX Input 1 Source*/ + { 0x00000b28, 0x0000 }, /* R2856 (0xb28) - ISRC1INT2MIX Input 1 Source*/ + { 0x00000b30, 0x0000 }, /* R2864 (0xb30) - ISRC1INT3MIX Input 1 Source*/ + { 0x00000b38, 0x0000 }, /* R2872 (0xb38) - ISRC1INT4MIX Input 1 Source*/ + { 0x00000b40, 0x0000 }, /* R2880 (0xb40) - ISRC2DEC1MIX Input 1 Source*/ + { 0x00000b48, 0x0000 }, /* R2888 (0xb48) - ISRC2DEC2MIX Input 1 Source*/ + { 0x00000b50, 0x0000 }, /* R2896 (0xb50) - ISRC2DEC3MIX Input 1 Source*/ + { 0x00000b58, 0x0000 }, /* R2904 (0xb58) - ISRC2DEC4MIX Input 1 Source*/ + { 0x00000b60, 0x0000 }, /* R2912 (0xb60) - ISRC2INT1MIX Input 1 Source*/ + { 0x00000b68, 0x0000 }, /* R2920 (0xb68) - ISRC2INT2MIX Input 1 Source*/ + { 0x00000b70, 0x0000 }, /* R2928 (0xb70) - ISRC2INT3MIX Input 1 Source*/ + { 0x00000b78, 0x0000 }, /* R2936 (0xb78) - ISRC2INT4MIX Input 1 Source*/ + { 0x00000b80, 0x0000 }, /* R2944 (0xb80) - ISRC3DEC1MIX Input 1 Source*/ + { 0x00000b88, 0x0000 }, /* R2952 (0xb88) - ISRC3DEC2MIX Input 1 Source*/ + { 0x00000ba0, 0x0000 }, /* R2976 (0xb80) - ISRC3INT1MIX Input 1 Source*/ + { 0x00000ba8, 0x0000 }, /* R2984 (0xb88) - ISRC3INT2MIX Input 1 Source*/ + { 0x00000bc0, 0x0000 }, /* R3008 (0xbc0) - ISRC4DEC1MIX Input 1 Source */ + { 0x00000bc8, 0x0000 }, /* R3016 (0xbc8) - ISRC4DEC2MIX Input 1 Source */ + { 0x00000be0, 0x0000 }, /* R3040 (0xbe0) - ISRC4INT1MIX Input 1 Source */ + { 0x00000be8, 0x0000 }, /* R3048 (0xbe8) - ISRC4INT2MIX Input 1 Source */ + { 0x00000c00, 0x0000 }, /* R3072 (0xc00) - DSP6LMIX Input 1 Source */ + { 0x00000c01, 0x0080 }, /* R3073 (0xc01) - DSP6LMIX Input 1 Volume */ + { 0x00000c02, 0x0000 }, /* R3074 (0xc02) - DSP6LMIX Input 2 Source */ + { 0x00000c03, 0x0080 }, /* R3075 (0xc03) - DSP6LMIX Input 2 Volume */ + { 0x00000c04, 0x0000 }, /* R3076 (0xc04) - DSP6LMIX Input 3 Source */ + { 0x00000c05, 0x0080 }, /* R3077 (0xc05) - DSP6LMIX Input 3 Volume */ + { 0x00000c06, 0x0000 }, /* R3078 (0xc06) - DSP6LMIX Input 4 Source */ + { 0x00000c07, 0x0080 }, /* R3079 (0xc07) - DSP6LMIX Input 4 Volume */ + { 0x00000c08, 0x0000 }, /* R3080 (0xc08) - DSP6RMIX Input 1 Source */ + { 0x00000c09, 0x0080 }, /* R3081 (0xc09) - DSP6RMIX Input 1 Volume */ + { 0x00000c0a, 0x0000 }, /* R3082 (0xc0a) - DSP6RMIX Input 2 Source */ + { 0x00000c0b, 0x0080 }, /* R3083 (0xc0b) - DSP6RMIX Input 2 Volume */ + { 0x00000c0c, 0x0000 }, /* R3084 (0xc0c) - DSP6RMIX Input 3 Source */ + { 0x00000c0d, 0x0080 }, /* R3085 (0xc0d) - DSP6RMIX Input 3 Volume */ + { 0x00000c0e, 0x0000 }, /* R3086 (0xc0e) - DSP6RMIX Input 4 Source */ + { 0x00000c0f, 0x0080 }, /* R3087 (0xc0f) - DSP6RMIX Input 4 Volume */ + { 0x00000c10, 0x0000 }, /* R3088 (0xc10) - DSP6AUX1MIX Input 1 Source */ + { 0x00000c18, 0x0000 }, /* R3088 (0xc18) - DSP6AUX2MIX Input 1 Source */ + { 0x00000c20, 0x0000 }, /* R3088 (0xc20) - DSP6AUX3MIX Input 1 Source */ + { 0x00000c28, 0x0000 }, /* R3088 (0xc28) - DSP6AUX4MIX Input 1 Source */ + { 0x00000c30, 0x0000 }, /* R3088 (0xc30) - DSP6AUX5MIX Input 1 Source */ + { 0x00000c38, 0x0000 }, /* R3088 (0xc38) - DSP6AUX6MIX Input 1 Source */ + { 0x00000c40, 0x0000 }, /* R3136 (0xc40) - DSP7LMIX Input 1 Source */ + { 0x00000c41, 0x0080 }, /* R3137 (0xc41) - DSP7LMIX Input 1 Volume */ + { 0x00000c42, 0x0000 }, /* R3138 (0xc42) - DSP7LMIX Input 2 Source */ + { 0x00000c43, 0x0080 }, /* R3139 (0xc43) - DSP7LMIX Input 2 Volume */ + { 0x00000c44, 0x0000 }, /* R3140 (0xc44) - DSP7LMIX Input 3 Source */ + { 0x00000c45, 0x0080 }, /* R3141 (0xc45) - DSP7lMIX Input 3 Volume */ + { 0x00000c46, 0x0000 }, /* R3142 (0xc46) - DSP7lMIX Input 4 Source */ + { 0x00000c47, 0x0080 }, /* R3143 (0xc47) - DSP7LMIX Input 4 Volume */ + { 0x00000c48, 0x0000 }, /* R3144 (0xc48) - DSP7RMIX Input 1 Source */ + { 0x00000c49, 0x0080 }, /* R3145 (0xc49) - DSP7RMIX Input 1 Volume */ + { 0x00000c4a, 0x0000 }, /* R3146 (0xc4a) - DSP7RMIX Input 2 Source */ + { 0x00000c4b, 0x0080 }, /* R3147 (0xc4b) - DSP7RMIX Input 2 Volume */ + { 0x00000c4c, 0x0000 }, /* R3148 (0xc4c) - DSP7RMIX Input 3 Source */ + { 0x00000c4d, 0x0080 }, /* R3159 (0xc4d) - DSP7RMIX Input 3 Volume */ + { 0x00000c4e, 0x0000 }, /* R3150 (0xc4e) - DSP7RMIX Input 4 Source */ + { 0x00000c4f, 0x0080 }, /* R3151 (0xc4f) - DSP7RMIX Input 4 Volume */ + { 0x00000c50, 0x0000 }, /* R3152 (0xc50) - DSP7AUX1MIX Input 1 Source */ + { 0x00000c58, 0x0000 }, /* R3160 (0xc58) - DSP7AUX2MIX Input 1 Source */ + { 0x00000c60, 0x0000 }, /* R3168 (0xc60) - DSP7AUX3MIX Input 1 Source */ + { 0x00000c68, 0x0000 }, /* R3176 (0xc68) - DSP7AUX4MIX Input 1 Source */ + { 0x00000c70, 0x0000 }, /* R3184 (0xc70) - DSP7AUX5MIX Input 1 Source */ + { 0x00000c78, 0x0000 }, /* R3192 (0xc78) - DSP7AUX6MIX Input 1 Source */ + { 0x00000dc0, 0x0000 }, /* R3520 (0xdc0) - DFC1MIX Input 1 Source */ + { 0x00000dc8, 0x0000 }, /* R3528 (0xdc8) - DFC2MIX Input 1 Source */ + { 0x00000dd0, 0x0000 }, /* R3536 (0xdd0) - DFC3MIX Input 1 Source */ + { 0x00000dd8, 0x0000 }, /* R3544 (0xdd8) - DFC4MIX Input 1 Source */ + { 0x00000de0, 0x0000 }, /* R3552 (0xde0) - DFC5MIX Input 1 Source */ + { 0x00000de8, 0x0000 }, /* R3560 (0xde8) - DFC6MIX Input 1 Source */ + { 0x00000df0, 0x0000 }, /* R3568 (0xdf0) - DFC7MIX Input 1 Source */ + { 0x00000df8, 0x0000 }, /* R3576 (0xdf8) - DFC8MIX Input 1 Source */ + { 0x00000e00, 0x0000 }, /* R3584 (0xe00) - FX_Ctrl1 */ + { 0x00000e10, 0x6318 }, /* R3600 (0xe10) - EQ1_1 */ + { 0x00000e11, 0x6300 }, /* R3601 (0xe11) - EQ1_2 */ + { 0x00000e12, 0x0fc8 }, /* R3602 (0xe12) - EQ1_3 */ + { 0x00000e13, 0x03fe }, /* R3603 (0xe13) - EQ1_4 */ + { 0x00000e14, 0x00e0 }, /* R3604 (0xe14) - EQ1_5 */ + { 0x00000e15, 0x1ec4 }, /* R3605 (0xe15) - EQ1_6 */ + { 0x00000e16, 0xf136 }, /* R3606 (0xe16) - EQ1_7 */ + { 0x00000e17, 0x0409 }, /* R3607 (0xe17) - EQ1_8 */ + { 0x00000e18, 0x04cc }, /* R3608 (0xe18) - EQ1_9 */ + { 0x00000e19, 0x1c9b }, /* R3609 (0xe19) - EQ1_10 */ + { 0x00000e1a, 0xf337 }, /* R3610 (0xe1a) - EQ1_11 */ + { 0x00000e1b, 0x040b }, /* R3611 (0xe1b) - EQ1_12 */ + { 0x00000e1c, 0x0cbb }, /* R3612 (0xe1c) - EQ1_13 */ + { 0x00000e1d, 0x16f8 }, /* R3613 (0xe1d) - EQ1_14 */ + { 0x00000e1e, 0xf7d9 }, /* R3614 (0xe1e) - EQ1_15 */ + { 0x00000e1f, 0x040a }, /* R3615 (0xe1f) - EQ1_16 */ + { 0x00000e20, 0x1f14 }, /* R3616 (0xe20) - EQ1_17 */ + { 0x00000e21, 0x058c }, /* R3617 (0xe21) - EQ1_18 */ + { 0x00000e22, 0x0563 }, /* R3618 (0xe22) - EQ1_19 */ + { 0x00000e23, 0x4000 }, /* R3619 (0xe23) - EQ1_20 */ + { 0x00000e24, 0x0b75 }, /* R3620 (0xe24) - EQ1_21 */ + { 0x00000e26, 0x6318 }, /* R3622 (0xe26) - EQ2_1 */ + { 0x00000e27, 0x6300 }, /* R3623 (0xe27) - EQ2_2 */ + { 0x00000e28, 0x0fc8 }, /* R3624 (0xe28) - EQ2_3 */ + { 0x00000e29, 0x03fe }, /* R3625 (0xe29) - EQ2_4 */ + { 0x00000e2a, 0x00e0 }, /* R3626 (0xe2a) - EQ2_5 */ + { 0x00000e2b, 0x1ec4 }, /* R3627 (0xe2b) - EQ2_6 */ + { 0x00000e2c, 0xf136 }, /* R3628 (0xe2c) - EQ2_7 */ + { 0x00000e2d, 0x0409 }, /* R3629 (0xe2d) - EQ2_8 */ + { 0x00000e2e, 0x04cc }, /* R3630 (0xe2e) - EQ2_9 */ + { 0x00000e2f, 0x1c9b }, /* R3631 (0xe2f) - EQ2_10 */ + { 0x00000e30, 0xf337 }, /* R3632 (0xe30) - EQ2_11 */ + { 0x00000e31, 0x040b }, /* R3633 (0xe31) - EQ2_12 */ + { 0x00000e32, 0x0cbb }, /* R3634 (0xe32) - EQ2_13 */ + { 0x00000e33, 0x16f8 }, /* R3635 (0xe33) - EQ2_14 */ + { 0x00000e34, 0xf7d9 }, /* R3636 (0xe34) - EQ2_15 */ + { 0x00000e35, 0x040a }, /* R3637 (0xe35) - EQ2_16 */ + { 0x00000e36, 0x1f14 }, /* R3638 (0xe36) - EQ2_17 */ + { 0x00000e37, 0x058c }, /* R3639 (0xe37) - EQ2_18 */ + { 0x00000e38, 0x0563 }, /* R3640 (0xe38) - EQ2_19 */ + { 0x00000e39, 0x4000 }, /* R3641 (0xe39) - EQ2_20 */ + { 0x00000e3a, 0x0b75 }, /* R3642 (0xe3a) - EQ2_21 */ + { 0x00000e3c, 0x6318 }, /* R3644 (0xe3c) - EQ3_1 */ + { 0x00000e3d, 0x6300 }, /* R3645 (0xe3d) - EQ3_2 */ + { 0x00000e3e, 0x0fc8 }, /* R3646 (0xe3e) - EQ3_3 */ + { 0x00000e3f, 0x03fe }, /* R3647 (0xe3f) - EQ3_4 */ + { 0x00000e40, 0x00e0 }, /* R3648 (0xe40) - EQ3_5 */ + { 0x00000e41, 0x1ec4 }, /* R3649 (0xe41) - EQ3_6 */ + { 0x00000e42, 0xf136 }, /* R3650 (0xe42) - EQ3_7 */ + { 0x00000e43, 0x0409 }, /* R3651 (0xe43) - EQ3_8 */ + { 0x00000e44, 0x04cc }, /* R3652 (0xe44) - EQ3_9 */ + { 0x00000e45, 0x1c9b }, /* R3653 (0xe45) - EQ3_10 */ + { 0x00000e46, 0xf337 }, /* R3654 (0xe46) - EQ3_11 */ + { 0x00000e47, 0x040b }, /* R3655 (0xe47) - EQ3_12 */ + { 0x00000e48, 0x0cbb }, /* R3656 (0xe48) - EQ3_13 */ + { 0x00000e49, 0x16f8 }, /* R3657 (0xe49) - EQ3_14 */ + { 0x00000e4a, 0xf7d9 }, /* R3658 (0xe4a) - EQ3_15 */ + { 0x00000e4b, 0x040a }, /* R3659 (0xe4b) - EQ3_16 */ + { 0x00000e4c, 0x1f14 }, /* R3660 (0xe4c) - EQ3_17 */ + { 0x00000e4d, 0x058c }, /* R3661 (0xe4d) - EQ3_18 */ + { 0x00000e4e, 0x0563 }, /* R3662 (0xe4e) - EQ3_19 */ + { 0x00000e4f, 0x4000 }, /* R3663 (0xe4f) - EQ3_20 */ + { 0x00000e50, 0x0b75 }, /* R3664 (0xe50) - EQ3_21 */ + { 0x00000e52, 0x6318 }, /* R3666 (0xe52) - EQ4_1 */ + { 0x00000e53, 0x6300 }, /* R3667 (0xe53) - EQ4_2 */ + { 0x00000e54, 0x0fc8 }, /* R3668 (0xe54) - EQ4_3 */ + { 0x00000e55, 0x03fe }, /* R3669 (0xe55) - EQ4_4 */ + { 0x00000e56, 0x00e0 }, /* R3670 (0xe56) - EQ4_5 */ + { 0x00000e57, 0x1ec4 }, /* R3671 (0xe57) - EQ4_6 */ + { 0x00000e58, 0xf136 }, /* R3672 (0xe58) - EQ4_7 */ + { 0x00000e59, 0x0409 }, /* R3673 (0xe59) - EQ4_8 */ + { 0x00000e5a, 0x04cc }, /* R3674 (0xe5a) - EQ4_9 */ + { 0x00000e5b, 0x1c9b }, /* R3675 (0xe5b) - EQ4_10 */ + { 0x00000e5c, 0xf337 }, /* R3676 (0xe5c) - EQ4_11 */ + { 0x00000e5d, 0x040b }, /* R3677 (0xe5d) - EQ4_12 */ + { 0x00000e5e, 0x0cbb }, /* R3678 (0xe5e) - EQ4_13 */ + { 0x00000e5f, 0x16f8 }, /* R3679 (0xe5f) - EQ4_14 */ + { 0x00000e60, 0xf7d9 }, /* R3680 (0xe60) - EQ4_15 */ + { 0x00000e61, 0x040a }, /* R3681 (0xe61) - EQ4_16 */ + { 0x00000e62, 0x1f14 }, /* R3682 (0xe62) - EQ4_17 */ + { 0x00000e63, 0x058c }, /* R3683 (0xe63) - EQ4_18 */ + { 0x00000e64, 0x0563 }, /* R3684 (0xe64) - EQ4_19 */ + { 0x00000e65, 0x4000 }, /* R3685 (0xe65) - EQ4_20 */ + { 0x00000e66, 0x0b75 }, /* R3686 (0xe66) - EQ4_21 */ + { 0x00000e80, 0x0018 }, /* R3712 (0xe80) - DRC1 ctrl1 */ + { 0x00000e81, 0x0933 }, /* R3713 (0xe81) - DRC1 ctrl2 */ + { 0x00000e82, 0x0018 }, /* R3714 (0xe82) - DRC1 ctrl3 */ + { 0x00000e83, 0x0000 }, /* R3715 (0xe83) - DRC1 ctrl4 */ + { 0x00000e84, 0x0000 }, /* R3716 (0xe84) - DRC1 ctrl5 */ + { 0x00000e88, 0x0018 }, /* R3720 (0xe88) - DRC2 ctrl1 */ + { 0x00000e89, 0x0933 }, /* R3721 (0xe89) - DRC2 ctrl2 */ + { 0x00000e8a, 0x0018 }, /* R3722 (0xe8a) - DRC2 ctrl3 */ + { 0x00000e8b, 0x0000 }, /* R3723 (0xe8b) - DRC2 ctrl4 */ + { 0x00000e8c, 0x0000 }, /* R3724 (0xe8c) - DRC2 ctrl5 */ + { 0x00000ec0, 0x0000 }, /* R3776 (0xec0) - HPLPF1_1 */ + { 0x00000ec1, 0x0000 }, /* R3777 (0xec1) - HPLPF1_2 */ + { 0x00000ec4, 0x0000 }, /* R3780 (0xec4) - HPLPF2_1 */ + { 0x00000ec5, 0x0000 }, /* R3781 (0xec5) - HPLPF2_2 */ + { 0x00000ec8, 0x0000 }, /* R3784 (0xec8) - HPLPF3_1 */ + { 0x00000ec9, 0x0000 }, /* R3785 (0xec9) - HPLPF3_2 */ + { 0x00000ecc, 0x0000 }, /* R3788 (0xecc) - HPLPF4_1 */ + { 0x00000ecd, 0x0000 }, /* R3789 (0xecd) - HPLPF4_2 */ + { 0x00000ed0, 0x0000 }, /* R3792 (0xed0) - ASRC2_ENABLE */ + { 0x00000ed2, 0x0000 }, /* R3794 (0xed2) - ASRC2_RATE1 */ + { 0x00000ed3, 0x4000 }, /* R3795 (0xed3) - ASRC2_RATE2 */ + { 0x00000ee0, 0x0000 }, /* R3808 (0xee0) - ASRC1_ENABLE */ + { 0x00000ee2, 0x0000 }, /* R3810 (0xee2) - ASRC1_RATE1 */ + { 0x00000ee3, 0x4000 }, /* R3811 (0xee3) - ASRC1_RATE2 */ + { 0x00000ef0, 0x0000 }, /* R3824 (0xef0) - ISRC 1 CTRL 1 */ + { 0x00000ef1, 0x0001 }, /* R3825 (0xef1) - ISRC 1 CTRL 2 */ + { 0x00000ef2, 0x0000 }, /* R3826 (0xef2) - ISRC 1 CTRL 3 */ + { 0x00000ef3, 0x0000 }, /* R3827 (0xef3) - ISRC 2 CTRL 1 */ + { 0x00000ef4, 0x0001 }, /* R3828 (0xef4) - ISRC 2 CTRL 2 */ + { 0x00000ef5, 0x0000 }, /* R3829 (0xef5) - ISRC 2 CTRL 3 */ + { 0x00000ef6, 0x0000 }, /* R3830 (0xef6) - ISRC 3 CTRL 1 */ + { 0x00000ef7, 0x0001 }, /* R3831 (0xef7) - ISRC 3 CTRL 2 */ + { 0x00000ef8, 0x0000 }, /* R3832 (0xef8) - ISRC 3 CTRL 3 */ + { 0x00000ef9, 0x0000 }, /* R3833 (0xef9) - ISRC 4 CTRL 1 */ + { 0x00000efa, 0x0001 }, /* R3834 (0xefa) - ISRC 4 CTRL 2 */ + { 0x00000efb, 0x0000 }, /* R3835 (0xefb) - ISRC 4 CTRL 3 */ + { 0x00000f01, 0x0000 }, /* R3841 (0xf01) - ANC_SRC */ + { 0x00000f02, 0x0000 }, /* R3842 (0xf02) - DSP Status */ + { 0x00000f08, 0x001c }, /* R3848 (0xf08) - ANC Coefficient */ + { 0x00000f09, 0x0000 }, /* R3849 (0xf09) - ANC Coefficient */ + { 0x00000f0a, 0x0000 }, /* R3850 (0xf0a) - ANC Coefficient */ + { 0x00000f0b, 0x0000 }, /* R3851 (0xf0b) - ANC Coefficient */ + { 0x00000f0c, 0x0000 }, /* R3852 (0xf0c) - ANC Coefficient */ + { 0x00000f0d, 0x0000 }, /* R3853 (0xf0d) - ANC Coefficient */ + { 0x00000f0e, 0x0000 }, /* R3854 (0xf0e) - ANC Coefficient */ + { 0x00000f0f, 0x0000 }, /* R3855 (0xf0f) - ANC Coefficient */ + { 0x00000f10, 0x0000 }, /* R3856 (0xf10) - ANC Coefficient */ + { 0x00000f11, 0x0000 }, /* R3857 (0xf11) - ANC Coefficient */ + { 0x00000f12, 0x0000 }, /* R3858 (0xf12) - ANC Coefficient */ + { 0x00000f15, 0x0000 }, /* R3861 (0xf15) - FCL Filter Control */ + { 0x00000f17, 0x0004 }, /* R3863 (0xf17) - FCL ADC Reformatter Control */ + { 0x00000f18, 0x0004 }, /* R3864 (0xf18) - ANC Coefficient */ + { 0x00000f19, 0x0002 }, /* R3865 (0xf19) - ANC Coefficient */ + { 0x00000f1a, 0x0000 }, /* R3866 (0xf1a) - ANC Coefficient */ + { 0x00000f1b, 0x0010 }, /* R3867 (0xf1b) - ANC Coefficient */ + { 0x00000f1c, 0x0000 }, /* R3868 (0xf1c) - ANC Coefficient */ + { 0x00000f1d, 0x0000 }, /* R3869 (0xf1d) - ANC Coefficient */ + { 0x00000f1e, 0x0000 }, /* R3870 (0xf1e) - ANC Coefficient */ + { 0x00000f1f, 0x0000 }, /* R3871 (0xf1f) - ANC Coefficient */ + { 0x00000f20, 0x0000 }, /* R3872 (0xf20) - ANC Coefficient */ + { 0x00000f21, 0x0000 }, /* R3873 (0xf21) - ANC Coefficient */ + { 0x00000f22, 0x0000 }, /* R3874 (0xf22) - ANC Coefficient */ + { 0x00000f23, 0x0000 }, /* R3875 (0xf23) - ANC Coefficient */ + { 0x00000f24, 0x0000 }, /* R3876 (0xf24) - ANC Coefficient */ + { 0x00000f25, 0x0000 }, /* R3877 (0xf25) - ANC Coefficient */ + { 0x00000f26, 0x0000 }, /* R3878 (0xf26) - ANC Coefficient */ + { 0x00000f27, 0x0000 }, /* R3879 (0xf27) - ANC Coefficient */ + { 0x00000f28, 0x0000 }, /* R3880 (0xf28) - ANC Coefficient */ + { 0x00000f29, 0x0000 }, /* R3881 (0xf29) - ANC Coefficient */ + { 0x00000f2a, 0x0000 }, /* R3882 (0xf2a) - ANC Coefficient */ + { 0x00000f2b, 0x0000 }, /* R3883 (0xf2b) - ANC Coefficient */ + { 0x00000f2c, 0x0000 }, /* R3884 (0xf2c) - ANC Coefficient */ + { 0x00000f2d, 0x0000 }, /* R3885 (0xf2d) - ANC Coefficient */ + { 0x00000f2e, 0x0000 }, /* R3886 (0xf2e) - ANC Coefficient */ + { 0x00000f2f, 0x0000 }, /* R3887 (0xf2f) - ANC Coefficient */ + { 0x00000f30, 0x0000 }, /* R3888 (0xf30) - ANC Coefficient */ + { 0x00000f31, 0x0000 }, /* R3889 (0xf31) - ANC Coefficient */ + { 0x00000f32, 0x0000 }, /* R3890 (0xf32) - ANC Coefficient */ + { 0x00000f33, 0x0000 }, /* R3891 (0xf33) - ANC Coefficient */ + { 0x00000f34, 0x0000 }, /* R3892 (0xf34) - ANC Coefficient */ + { 0x00000f35, 0x0000 }, /* R3893 (0xf35) - ANC Coefficient */ + { 0x00000f36, 0x0000 }, /* R3894 (0xf36) - ANC Coefficient */ + { 0x00000f37, 0x0000 }, /* R3895 (0xf37) - ANC Coefficient */ + { 0x00000f38, 0x0000 }, /* R3896 (0xf38) - ANC Coefficient */ + { 0x00000f39, 0x0000 }, /* R3897 (0xf39) - ANC Coefficient */ + { 0x00000f3a, 0x0000 }, /* R3898 (0xf3a) - ANC Coefficient */ + { 0x00000f3b, 0x0000 }, /* R3899 (0xf3b) - ANC Coefficient */ + { 0x00000f3c, 0x0000 }, /* R3900 (0xf3c) - ANC Coefficient */ + { 0x00000f3d, 0x0000 }, /* R3901 (0xf3d) - ANC Coefficient */ + { 0x00000f3e, 0x0000 }, /* R3902 (0xf3e) - ANC Coefficient */ + { 0x00000f3f, 0x0000 }, /* R3903 (0xf3f) - ANC Coefficient */ + { 0x00000f40, 0x0000 }, /* R3904 (0xf40) - ANC Coefficient */ + { 0x00000f41, 0x0000 }, /* R3905 (0xf41) - ANC Coefficient */ + { 0x00000f42, 0x0000 }, /* R3906 (0xf42) - ANC Coefficient */ + { 0x00000f43, 0x0000 }, /* R3907 (0xf43) - ANC Coefficient */ + { 0x00000f44, 0x0000 }, /* R3908 (0xf44) - ANC Coefficient */ + { 0x00000f45, 0x0000 }, /* R3909 (0xf45) - ANC Coefficient */ + { 0x00000f46, 0x0000 }, /* R3910 (0xf46) - ANC Coefficient */ + { 0x00000f47, 0x0000 }, /* R3911 (0xf47) - ANC Coefficient */ + { 0x00000f48, 0x0000 }, /* R3912 (0xf48) - ANC Coefficient */ + { 0x00000f49, 0x0000 }, /* R3913 (0xf49) - ANC Coefficient */ + { 0x00000f4a, 0x0000 }, /* R3914 (0xf4a) - ANC Coefficient */ + { 0x00000f4b, 0x0000 }, /* R3915 (0xf4b) - ANC Coefficient */ + { 0x00000f4c, 0x0000 }, /* R3916 (0xf4c) - ANC Coefficient */ + { 0x00000f4d, 0x0000 }, /* R3917 (0xf4d) - ANC Coefficient */ + { 0x00000f4e, 0x0000 }, /* R3918 (0xf4e) - ANC Coefficient */ + { 0x00000f4f, 0x0000 }, /* R3919 (0xf4f) - ANC Coefficient */ + { 0x00000f50, 0x0000 }, /* R3920 (0xf50) - ANC Coefficient */ + { 0x00000f51, 0x0000 }, /* R3921 (0xf51) - ANC Coefficient */ + { 0x00000f52, 0x0000 }, /* R3922 (0xf52) - ANC Coefficient */ + { 0x00000f53, 0x0000 }, /* R3923 (0xf53) - ANC Coefficient */ + { 0x00000f54, 0x0000 }, /* R3924 (0xf54) - ANC Coefficient */ + { 0x00000f55, 0x0000 }, /* R3925 (0xf55) - ANC Coefficient */ + { 0x00000f56, 0x0000 }, /* R3926 (0xf56) - ANC Coefficient */ + { 0x00000f57, 0x0000 }, /* R3927 (0xf57) - ANC Coefficient */ + { 0x00000f58, 0x0000 }, /* R3928 (0xf58) - ANC Coefficient */ + { 0x00000f59, 0x0000 }, /* R3929 (0xf59) - ANC Coefficient */ + { 0x00000f5a, 0x0000 }, /* R3930 (0xf5a) - ANC Coefficient */ + { 0x00000f5b, 0x0000 }, /* R3931 (0xf5b) - ANC Coefficient */ + { 0x00000f5c, 0x0000 }, /* R3932 (0xf5c) - ANC Coefficient */ + { 0x00000f5d, 0x0000 }, /* R3933 (0xf5d) - ANC Coefficient */ + { 0x00000f5e, 0x0000 }, /* R3934 (0xf5e) - ANC Coefficient */ + { 0x00000f5f, 0x0000 }, /* R3935 (0xf5f) - ANC Coefficient */ + { 0x00000f60, 0x0000 }, /* R3936 (0xf60) - ANC Coefficient */ + { 0x00000f61, 0x0000 }, /* R3937 (0xf61) - ANC Coefficient */ + { 0x00000f62, 0x0000 }, /* R3938 (0xf62) - ANC Coefficient */ + { 0x00000f63, 0x0000 }, /* R3939 (0xf63) - ANC Coefficient */ + { 0x00000f64, 0x0000 }, /* R3940 (0xf64) - ANC Coefficient */ + { 0x00000f65, 0x0000 }, /* R3941 (0xf65) - ANC Coefficient */ + { 0x00000f66, 0x0000 }, /* R3942 (0xf66) - ANC Coefficient */ + { 0x00000f67, 0x0000 }, /* R3943 (0xf67) - ANC Coefficient */ + { 0x00000f68, 0x0000 }, /* R3944 (0xf68) - ANC Coefficient */ + { 0x00000f69, 0x0000 }, /* R3945 (0xf69) - ANC Coefficient */ + { 0x00000f71, 0x0000 }, /* R3953 (0xf71) - FCR Filter Control */ + { 0x00000f73, 0x0004 }, /* R3955 (0xf73) - FCR ADC Reformatter Control */ + { 0x00000f74, 0x0004 }, /* R3956 (0xf74) - ANC Coefficient */ + { 0x00000f75, 0x0002 }, /* R3957 (0xf75) - ANC Coefficient */ + { 0x00000f76, 0x0000 }, /* R3958 (0xf76) - ANC Coefficient */ + { 0x00000f77, 0x0010 }, /* R3959 (0xf77) - ANC Coefficient */ + { 0x00000f78, 0x0000 }, /* R3960 (0xf78) - ANC Coefficient */ + { 0x00000f79, 0x0000 }, /* R3961 (0xf79) - ANC Coefficient */ + { 0x00000f7a, 0x0000 }, /* R3962 (0xf7a) - ANC Coefficient */ + { 0x00000f7b, 0x0000 }, /* R3963 (0xf7b) - ANC Coefficient */ + { 0x00000f7c, 0x0000 }, /* R3964 (0xf7c) - ANC Coefficient */ + { 0x00000f7d, 0x0000 }, /* R3965 (0xf7d) - ANC Coefficient */ + { 0x00000f7e, 0x0000 }, /* R3966 (0xf7e) - ANC Coefficient */ + { 0x00000f7f, 0x0000 }, /* R3967 (0xf7f) - ANC Coefficient */ + { 0x00000f80, 0x0000 }, /* R3968 (0xf80) - ANC Coefficient */ + { 0x00000f81, 0x0000 }, /* R3969 (0xf81) - ANC Coefficient */ + { 0x00000f82, 0x0000 }, /* R3970 (0xf82) - ANC Coefficient */ + { 0x00000f83, 0x0000 }, /* R3971 (0xf83) - ANC Coefficient */ + { 0x00000f84, 0x0000 }, /* R3972 (0xf84) - ANC Coefficient */ + { 0x00000f85, 0x0000 }, /* R3973 (0xf85) - ANC Coefficient */ + { 0x00000f86, 0x0000 }, /* R3974 (0xf86) - ANC Coefficient */ + { 0x00000f87, 0x0000 }, /* R3975 (0xf87) - ANC Coefficient */ + { 0x00000f88, 0x0000 }, /* R3976 (0xf88) - ANC Coefficient */ + { 0x00000f89, 0x0000 }, /* R3977 (0xf89) - ANC Coefficient */ + { 0x00000f8a, 0x0000 }, /* R3978 (0xf8a) - ANC Coefficient */ + { 0x00000f8b, 0x0000 }, /* R3979 (0xf8b) - ANC Coefficient */ + { 0x00000f8c, 0x0000 }, /* R3980 (0xf8c) - ANC Coefficient */ + { 0x00000f8d, 0x0000 }, /* R3981 (0xf8d) - ANC Coefficient */ + { 0x00000f8e, 0x0000 }, /* R3982 (0xf8e) - ANC Coefficient */ + { 0x00000f8f, 0x0000 }, /* R3983 (0xf8f) - ANC Coefficient */ + { 0x00000f90, 0x0000 }, /* R3984 (0xf90) - ANC Coefficient */ + { 0x00000f91, 0x0000 }, /* R3985 (0xf91) - ANC Coefficient */ + { 0x00000f92, 0x0000 }, /* R3986 (0xf92) - ANC Coefficient */ + { 0x00000f93, 0x0000 }, /* R3987 (0xf93) - ANC Coefficient */ + { 0x00000f94, 0x0000 }, /* R3988 (0xf94) - ANC Coefficient */ + { 0x00000f95, 0x0000 }, /* R3989 (0xf95) - ANC Coefficient */ + { 0x00000f96, 0x0000 }, /* R3990 (0xf96) - ANC Coefficient */ + { 0x00000f97, 0x0000 }, /* R3991 (0xf97) - ANC Coefficient */ + { 0x00000f98, 0x0000 }, /* R3992 (0xf98) - ANC Coefficient */ + { 0x00000f99, 0x0000 }, /* R3993 (0xf99) - ANC Coefficient */ + { 0x00000f9a, 0x0000 }, /* R3994 (0xf9a) - ANC Coefficient */ + { 0x00000f9b, 0x0000 }, /* R3995 (0xf9b) - ANC Coefficient */ + { 0x00000f9c, 0x0000 }, /* R3996 (0xf9c) - ANC Coefficient */ + { 0x00000f9d, 0x0000 }, /* R3997 (0xf9d) - ANC Coefficient */ + { 0x00000f9e, 0x0000 }, /* R3998 (0xf9e) - ANC Coefficient */ + { 0x00000f9f, 0x0000 }, /* R3999 (0xf9f) - ANC Coefficient */ + { 0x00000fa0, 0x0000 }, /* R4000 (0xfa0) - ANC Coefficient */ + { 0x00000fa1, 0x0000 }, /* R4001 (0xfa1) - ANC Coefficient */ + { 0x00000fa2, 0x0000 }, /* R4002 (0xfa2) - ANC Coefficient */ + { 0x00000fa3, 0x0000 }, /* R4003 (0xfa3) - ANC Coefficient */ + { 0x00000fa4, 0x0000 }, /* R4004 (0xfa4) - ANC Coefficient */ + { 0x00000fa5, 0x0000 }, /* R4005 (0xfa5) - ANC Coefficient */ + { 0x00000fa6, 0x0000 }, /* R4006 (0xfa6) - ANC Coefficient */ + { 0x00000fa7, 0x0000 }, /* R4007 (0xfa7) - ANC Coefficient */ + { 0x00000fa8, 0x0000 }, /* R4008 (0xfa8) - ANC Coefficient */ + { 0x00000fa9, 0x0000 }, /* R4009 (0xfa9) - ANC Coefficient */ + { 0x00000faa, 0x0000 }, /* R4010 (0xfaa) - ANC Coefficient */ + { 0x00000fab, 0x0000 }, /* R4011 (0xfab) - ANC Coefficient */ + { 0x00000fac, 0x0000 }, /* R4012 (0xfac) - ANC Coefficient */ + { 0x00000fad, 0x0000 }, /* R4013 (0xfad) - ANC Coefficient */ + { 0x00000fae, 0x0000 }, /* R4014 (0xfae) - ANC Coefficient */ + { 0x00000faf, 0x0000 }, /* R4015 (0xfaf) - ANC Coefficient */ + { 0x00000fb0, 0x0000 }, /* R4016 (0xfb0) - ANC Coefficient */ + { 0x00000fb1, 0x0000 }, /* R4017 (0xfb1) - ANC Coefficient */ + { 0x00000fb2, 0x0000 }, /* R4018 (0xfb2) - ANC Coefficient */ + { 0x00000fb3, 0x0000 }, /* R4019 (0xfb3) - ANC Coefficient */ + { 0x00000fb4, 0x0000 }, /* R4020 (0xfb4) - ANC Coefficient */ + { 0x00000fb5, 0x0000 }, /* R4021 (0xfb5) - ANC Coefficient */ + { 0x00000fb6, 0x0000 }, /* R4022 (0xfb6) - ANC Coefficient */ + { 0x00000fb7, 0x0000 }, /* R4023 (0xfb7) - ANC Coefficient */ + { 0x00000fb8, 0x0000 }, /* R4024 (0xfb8) - ANC Coefficient */ + { 0x00000fb9, 0x0000 }, /* R4025 (0xfb9) - ANC Coefficient */ + { 0x00000fba, 0x0000 }, /* R4026 (0xfba) - ANC Coefficient */ + { 0x00000fbb, 0x0000 }, /* R4027 (0xfbb) - ANC Coefficient */ + { 0x00000fbc, 0x0000 }, /* R4028 (0xfbc) - ANC Coefficient */ + { 0x00000fbd, 0x0000 }, /* R4029 (0xfbd) - ANC Coefficient */ + { 0x00000fbe, 0x0000 }, /* R4030 (0xfbe) - ANC Coefficient */ + { 0x00000fbf, 0x0000 }, /* R4031 (0xfbf) - ANC Coefficient */ + { 0x00000fc0, 0x0000 }, /* R4032 (0xfc0) - ANC Coefficient */ + { 0x00000fc1, 0x0000 }, /* R4033 (0xfc1) - ANC Coefficient */ + { 0x00000fc2, 0x0000 }, /* R4034 (0xfc2) - ANC Coefficient */ + { 0x00000fc3, 0x0000 }, /* R4035 (0xfc3) - ANC Coefficient */ + { 0x00000fc4, 0x0000 }, /* R4036 (0xfc4) - ANC Coefficient */ + { 0x00000fc5, 0x0000 }, /* R4037 (0xfc5) - ANC Coefficient */ + { 0x00001300, 0x050E }, /* R4864 (0x1300) - DAC Comp 1 */ + { 0x00001302, 0x0101 }, /* R4866 (0x1302) - DAC Comp 2 */ + { 0x00001380, 0x0425 }, /* R4992 (0x1380) - FRF Coefficient 1L 1 */ + { 0x00001381, 0xF6D8 }, /* R4993 (0x1381) - FRF Coefficient 1L 2 */ + { 0x00001382, 0x0632 }, /* R4994 (0x1382) - FRF Coefficient 1L 3 */ + { 0x00001383, 0xFEC8 }, /* R4995 (0x1383) - FRF Coefficient 1L 4 */ + { 0x00001390, 0x042F }, /* R5008 (0x1390) - FRF Coefficient 1R 1 */ + { 0x00001391, 0xF6CA }, /* R5009 (0x1391) - FRF Coefficient 1R 2 */ + { 0x00001392, 0x0637 }, /* R5010 (0x1392) - FRF Coefficient 1R 3 */ + { 0x00001393, 0xFEC8 }, /* R5011 (0x1393) - FRF Coefficient 1R 4 */ + { 0x000013a0, 0x0000 }, /* R5024 (0x13a0) - FRF Coefficient 2L 1 */ + { 0x000013a1, 0x0000 }, /* R5025 (0x13a1) - FRF Coefficient 2L 2 */ + { 0x000013a2, 0x0000 }, /* R5026 (0x13a2) - FRF Coefficient 2L 3 */ + { 0x000013a3, 0x0000 }, /* R5027 (0x13a3) - FRF Coefficient 2L 4 */ + { 0x000013b0, 0x0000 }, /* R5040 (0x13b0) - FRF Coefficient 2R 1 */ + { 0x000013b1, 0x0000 }, /* R5041 (0x13b1) - FRF Coefficient 2R 2 */ + { 0x000013b2, 0x0000 }, /* R5042 (0x13b2) - FRF Coefficient 2R 3 */ + { 0x000013b3, 0x0000 }, /* R5043 (0x13b3) - FRF Coefficient 2R 4 */ + { 0x000013c0, 0x0000 }, /* R5040 (0x13c0) - FRF Coefficient 3L 1 */ + { 0x000013c1, 0x0000 }, /* R5041 (0x13c1) - FRF Coefficient 3L 2 */ + { 0x000013c2, 0x0000 }, /* R5042 (0x13c2) - FRF Coefficient 3L 3 */ + { 0x000013c3, 0x0000 }, /* R5043 (0x13c3) - FRF Coefficient 3L 4 */ + { 0x000013d0, 0x0000 }, /* R5072 (0x13d0) - FRF Coefficient 3R 1 */ + { 0x000013d1, 0x0000 }, /* R5073 (0x13d1) - FRF Coefficient 3R 2 */ + { 0x000013d2, 0x0000 }, /* R5074 (0x13d2) - FRF Coefficient 3R 3 */ + { 0x000013d3, 0x0000 }, /* R5075 (0x13d3) - FRF Coefficient 3R 4 */ + { 0x00001400, 0x0000 }, /* R5120 (0x1400) - FRF Coefficient 5L 1 */ + { 0x00001401, 0x0000 }, /* R5121 (0x1401) - FRF Coefficient 5L 2 */ + { 0x00001402, 0x0000 }, /* R5122 (0x1402) - FRF Coefficient 5L 3 */ + { 0x00001403, 0x0000 }, /* R5123 (0x1403) - FRF Coefficient 5L 4 */ + { 0x00001410, 0x0000 }, /* R5136 (0x1410) - FRF Coefficient 5R 1 */ + { 0x00001411, 0x0000 }, /* R5137 (0x1411) - FRF Coefficient 5R 2 */ + { 0x00001412, 0x0000 }, /* R5138 (0x1412) - FRF Coefficient 5R 3 */ + { 0x00001413, 0x0000 }, /* R5139 (0x1413) - FRF Coefficient 5R 4 */ + { 0x00001480, 0x0000 }, /* R5248 (0x1480) - DFC1_CTRL */ + { 0x00001482, 0x1f00 }, /* R5250 (0x1482) - DFC1_RX */ + { 0x00001484, 0x1f00 }, /* R5252 (0x1486) - DFC1_TX */ + { 0x00001486, 0x0000 }, /* R5254 (0x1486) - DFC2_CTRL */ + { 0x00001488, 0x1f00 }, /* R5256 (0x1488) - DFC2_RX */ + { 0x0000148a, 0x1f00 }, /* R5258 (0x148a) - DFC2_TX */ + { 0x0000148c, 0x0000 }, /* R5260 (0x148c) - DFC3_CTRL */ + { 0x0000148e, 0x1f00 }, /* R5262 (0x148e) - DFC3_RX */ + { 0x00001490, 0x1f00 }, /* R5264 (0x1490) - DFC3_TX */ + { 0x00001492, 0x0000 }, /* R5266 (0x1492) - DFC4_CTRL */ + { 0x00001494, 0x1f00 }, /* R5268 (0x1494) - DFC4_RX */ + { 0x00001496, 0x1f00 }, /* R5270 (0x1496) - DFC4_TX */ + { 0x00001498, 0x0000 }, /* R5272 (0x1498) - DFC5_CTRL */ + { 0x0000149a, 0x1f00 }, /* R5274 (0x149a) - DFC5_RX */ + { 0x0000149c, 0x1f00 }, /* R5276 (0x149c) - DFC5_TX */ + { 0x0000149e, 0x0000 }, /* R5278 (0x149e) - DFC6_CTRL */ + { 0x000014a0, 0x1f00 }, /* R5280 (0x14a0) - DFC6_RX */ + { 0x000014a2, 0x1f00 }, /* R5282 (0x14a2) - DFC6_TX */ + { 0x000014a4, 0x0000 }, /* R5284 (0x14a4) - DFC7_CTRL */ + { 0x000014a6, 0x1f00 }, /* R5286 (0x14a6) - DFC7_RX */ + { 0x000014a8, 0x1f00 }, /* R5288 (0x14a8) - DFC7_TX */ + { 0x000014aa, 0x0000 }, /* R5290 (0x14aa) - DFC8_CTRL */ + { 0x000014ac, 0x1f00 }, /* R5292 (0x14ac) - DFC8_RX */ + { 0x000014ae, 0x1f00 }, /* R5294 (0x14ae) - DFC8_TX */ + { 0x00001700, 0x2001 }, /* R5888 (0x1700) - GPIO1 Control 1 */ + { 0x00001701, 0xf000 }, /* R5889 (0x1701) - GPIO1 Control 2 */ + { 0x00001702, 0x2001 }, /* R5890 (0x1702) - GPIO2 Control 1 */ + { 0x00001703, 0xf000 }, /* R5891 (0x1702) - GPIO2 Control 2 */ + { 0x00001704, 0x2001 }, /* R5892 (0x1704) - GPIO3 Control 1 */ + { 0x00001705, 0xf000 }, /* R5893 (0x1705) - GPIO3 Control 2 */ + { 0x00001706, 0x2001 }, /* R5894 (0x1706) - GPIO4 Control 1 */ + { 0x00001707, 0xf000 }, /* R5895 (0x1707) - GPIO4 Control 2 */ + { 0x00001708, 0x2001 }, /* R5896 (0x1708) - GPIO5 Control 1 */ + { 0x00001709, 0xf000 }, /* R5897 (0x1709) - GPIO5 Control 2 */ + { 0x0000170a, 0x2001 }, /* R5898 (0x170a) - GPIO6 Control 1 */ + { 0x0000170b, 0xf000 }, /* R5899 (0x170b) - GPIO6 Control 2 */ + { 0x0000170c, 0x2001 }, /* R5900 (0x170c) - GPIO7 Control 1 */ + { 0x0000170d, 0xf000 }, /* R5901 (0x170d) - GPIO7 Control 2 */ + { 0x0000170e, 0x2001 }, /* R5902 (0x170e) - GPIO8 Control 1 */ + { 0x0000170f, 0xf000 }, /* R5903 (0x170f) - GPIO8 Control 2 */ + { 0x00001710, 0x2001 }, /* R5904 (0x1710) - GPIO9 Control 1 */ + { 0x00001711, 0xf000 }, /* R5905 (0x1711) - GPIO9 Control 2 */ + { 0x00001712, 0x2001 }, /* R5906 (0x1712) - GPIO10 Control 1 */ + { 0x00001713, 0xf000 }, /* R5907 (0x1713) - GPIO10 Control 2 */ + { 0x00001714, 0x2001 }, /* R5908 (0x1714) - GPIO11 Control 1 */ + { 0x00001715, 0xf000 }, /* R5909 (0x1715) - GPIO11 Control 2 */ + { 0x00001716, 0x2001 }, /* R5910 (0x1716) - GPIO12 Control 1 */ + { 0x00001717, 0xf000 }, /* R5911 (0x1717) - GPIO12 Control 2 */ + { 0x00001718, 0x2001 }, /* R5912 (0x1718) - GPIO13 Control 1 */ + { 0x00001719, 0xf000 }, /* R5913 (0x1719) - GPIO13 Control 2 */ + { 0x0000171a, 0x2001 }, /* R5914 (0x171a) - GPIO14 Control 1 */ + { 0x0000171b, 0xf000 }, /* R5915 (0x171b) - GPIO14 Control 2 */ + { 0x0000171c, 0x2001 }, /* R5916 (0x171c) - GPIO15 Control 1 */ + { 0x0000171d, 0xf000 }, /* R5917 (0x171d) - GPIO15 Control 2 */ + { 0x0000171e, 0x2001 }, /* R5918 (0x171e) - GPIO16 Control 1 */ + { 0x0000171f, 0xf000 }, /* R5919 (0x171f) - GPIO16 Control 2 */ + { 0x00001720, 0x2001 }, /* R5920 (0x1720) - GPIO17 Control 1 */ + { 0x00001721, 0xf000 }, /* R5921 (0x1721) - GPIO17 Control 2 */ + { 0x00001722, 0x2001 }, /* R5922 (0x1722) - GPIO18 Control 1 */ + { 0x00001723, 0xf000 }, /* R5923 (0x1723) - GPIO18 Control 2 */ + { 0x00001724, 0x2001 }, /* R5924 (0x1724) - GPIO19 Control 1 */ + { 0x00001725, 0xf000 }, /* R5925 (0x1725) - GPIO19 Control 2 */ + { 0x00001726, 0x2001 }, /* R5926 (0x1726) - GPIO20 Control 1 */ + { 0x00001727, 0xf000 }, /* R5927 (0x1727) - GPIO20 Control 2 */ + { 0x00001728, 0x2001 }, /* R5928 (0x1728) - GPIO21 Control 1 */ + { 0x00001729, 0xf000 }, /* R5929 (0x1729) - GPIO21 Control 2 */ + { 0x0000172a, 0x2001 }, /* R5930 (0x172a) - GPIO22 Control 1 */ + { 0x0000172b, 0xf000 }, /* R5931 (0x172b) - GPIO22 Control 2 */ + { 0x0000172c, 0x2001 }, /* R5932 (0x172c) - GPIO23 Control 1 */ + { 0x0000172d, 0xf000 }, /* R5933 (0x172d) - GPIO23 Control 2 */ + { 0x0000172e, 0x2001 }, /* R5934 (0x172e) - GPIO24 Control 1 */ + { 0x0000172f, 0xf000 }, /* R5935 (0x172f) - GPIO24 Control 2 */ + { 0x00001730, 0x2001 }, /* R5936 (0x1730) - GPIO25 Control 1 */ + { 0x00001731, 0xf000 }, /* R5937 (0x1731) - GPIO25 Control 2 */ + { 0x00001732, 0x2001 }, /* R5938 (0x1732) - GPIO26 Control 1 */ + { 0x00001733, 0xf000 }, /* R5939 (0x1733) - GPIO26 Control 2 */ + { 0x00001734, 0x2001 }, /* R5940 (0x1734) - GPIO27 Control 1 */ + { 0x00001735, 0xf000 }, /* R5941 (0x1735) - GPIO27 Control 2 */ + { 0x00001736, 0x2001 }, /* R5942 (0x1736) - GPIO28 Control 1 */ + { 0x00001737, 0xf000 }, /* R5943 (0x1737) - GPIO28 Control 2 */ + { 0x00001738, 0x2001 }, /* R5944 (0x1738) - GPIO29 Control 1 */ + { 0x00001739, 0xf000 }, /* R5945 (0x1739) - GPIO29 Control 2 */ + { 0x0000173a, 0x2001 }, /* R5946 (0x173a) - GPIO30 Control 1 */ + { 0x0000173b, 0xf000 }, /* R5947 (0x173b) - GPIO30 Control 2 */ + { 0x0000173c, 0x2001 }, /* R5948 (0x173c) - GPIO31 Control 1 */ + { 0x0000173d, 0xf000 }, /* R5949 (0x173d) - GPIO31 Control 2 */ + { 0x0000173e, 0x2001 }, /* R5950 (0x173e) - GPIO32 Control 1 */ + { 0x0000173f, 0xf000 }, /* R5951 (0x173f) - GPIO32 Control 2 */ + { 0x00001740, 0x2001 }, /* R5952 (0x1740) - GPIO33 Control 1 */ + { 0x00001741, 0xf000 }, /* R5953 (0x1741) - GPIO33 Control 2 */ + { 0x00001742, 0x2001 }, /* R5954 (0x1742) - GPIO34 Control 1 */ + { 0x00001743, 0xf000 }, /* R5955 (0x1743) - GPIO34 Control 2 */ + { 0x00001744, 0x2001 }, /* R5956 (0x1744) - GPIO35 Control 1 */ + { 0x00001745, 0xf000 }, /* R5957 (0x1745) - GPIO35 Control 2 */ + { 0x00001746, 0x2001 }, /* R5958 (0x1746) - GPIO36 Control 1 */ + { 0x00001747, 0xf000 }, /* R5959 (0x1747) - GPIO36 Control 2 */ + { 0x00001748, 0x2001 }, /* R5960 (0x1748) - GPIO37 Control 1 */ + { 0x00001749, 0xf000 }, /* R5961 (0x1749) - GPIO37 Control 2 */ + { 0x0000174a, 0x2001 }, /* R5962 (0x174a) - GPIO38 Control 1 */ + { 0x0000174b, 0xf000 }, /* R5963 (0x174b) - GPIO38 Control 2 */ + { 0x00001840, 0xffff }, /* R6208 (0x1840) - IRQ1 Mask 1 */ + { 0x00001841, 0xffff }, /* R6209 (0x1841) - IRQ1 Mask 2 */ + { 0x00001842, 0xffff }, /* R6210 (0x1842) - IRQ1 Mask 3 */ + { 0x00001843, 0xffff }, /* R6211 (0x1843) - IRQ1 Mask 4 */ + { 0x00001844, 0xffff }, /* R6212 (0x1844) - IRQ1 Mask 5 */ + { 0x00001845, 0xffff }, /* R6213 (0x1845) - IRQ1 Mask 6 */ + { 0x00001846, 0xffff }, /* R6214 (0x1846) - IRQ1 Mask 7 */ + { 0x00001847, 0xffff }, /* R6215 (0x1847) - IRQ1 Mask 8 */ + { 0x00001848, 0xffff }, /* R6216 (0x1848) - IRQ1 Mask 9 */ + { 0x00001849, 0xffff }, /* R6217 (0x1849) - IRQ1 Mask 10 */ + { 0x0000184a, 0xffff }, /* R6218 (0x184a) - IRQ1 Mask 11 */ + { 0x0000184b, 0xffff }, /* R6219 (0x184b) - IRQ1 Mask 12 */ + { 0x0000184c, 0xffff }, /* R6220 (0x184c) - IRQ1 Mask 13 */ + { 0x0000184d, 0xffff }, /* R6221 (0x184d) - IRQ1 Mask 14 */ + { 0x0000184e, 0xffff }, /* R6222 (0x184e) - IRQ1 Mask 15 */ + { 0x0000184f, 0xffff }, /* R6223 (0x184f) - IRQ1 Mask 16 */ + { 0x00001850, 0xffff }, /* R6224 (0x1850) - IRQ1 Mask 17 */ + { 0x00001851, 0xffff }, /* R6225 (0x1851) - IRQ1 Mask 18 */ + { 0x00001852, 0xffff }, /* R6226 (0x1852) - IRQ1 Mask 19 */ + { 0x00001853, 0xffff }, /* R6227 (0x1853) - IRQ1 Mask 20 */ + { 0x00001854, 0xffff }, /* R6228 (0x1854) - IRQ1 Mask 21 */ + { 0x00001855, 0xffff }, /* R6229 (0x1855) - IRQ1 Mask 22 */ + { 0x00001856, 0xffff }, /* R6230 (0x1856) - IRQ1 Mask 23 */ + { 0x00001857, 0xffff }, /* R6231 (0x1857) - IRQ1 Mask 24 */ + { 0x00001858, 0xffff }, /* R6232 (0x1858) - IRQ1 Mask 25 */ + { 0x00001859, 0xffff }, /* R6233 (0x1859) - IRQ1 Mask 26 */ + { 0x0000185a, 0xffff }, /* R6234 (0x185a) - IRQ1 Mask 27 */ + { 0x0000185b, 0xffff }, /* R6235 (0x185b) - IRQ1 Mask 28 */ + { 0x0000185c, 0xffff }, /* R6236 (0x185c) - IRQ1 Mask 29 */ + { 0x0000185d, 0xffff }, /* R6237 (0x185d) - IRQ1 Mask 30 */ + { 0x0000185e, 0xffff }, /* R6238 (0x185e) - IRQ1 Mask 31 */ + { 0x0000185f, 0xffff }, /* R6239 (0x185f) - IRQ1 Mask 32 */ + { 0x00001860, 0xffff }, /* R6240 (0x1860) - IRQ1 Mask 33 */ + { 0x00001a06, 0x0000 }, /* R6662 (0x1a06) - Interrupt Debounce 7 */ + { 0x00001a80, 0x4400 }, /* R6784 (0x1a80) - IRQ1 CTRL */ +}; + +static bool cs47l90_is_adsp_memory(unsigned int reg) +{ + switch (reg) { + case 0x080000 ... 0x088ffe: + case 0x0a0000 ... 0x0a9ffe: + case 0x0c0000 ... 0x0c3ffe: + case 0x0e0000 ... 0x0e1ffe: + case 0x100000 ... 0x10effe: + case 0x120000 ... 0x12bffe: + case 0x136000 ... 0x137ffe: + case 0x140000 ... 0x14bffe: + case 0x160000 ... 0x161ffe: + case 0x180000 ... 0x18effe: + case 0x1a0000 ... 0x1b1ffe: + case 0x1b6000 ... 0x1b7ffe: + case 0x1c0000 ... 0x1cbffe: + case 0x1e0000 ... 0x1e1ffe: + case 0x200000 ... 0x208ffe: + case 0x220000 ... 0x229ffe: + case 0x240000 ... 0x243ffe: + case 0x260000 ... 0x261ffe: + case 0x280000 ... 0x288ffe: + case 0x2a0000 ... 0x2a9ffe: + case 0x2c0000 ... 0x2c3ffe: + case 0x2e0000 ... 0x2e1ffe: + case 0x300000 ... 0x308ffe: + case 0x320000 ... 0x333ffe: + case 0x340000 ... 0x353ffe: + case 0x360000 ... 0x361ffe: + case 0x380000 ... 0x388ffe: + case 0x3a0000 ... 0x3b3ffe: + case 0x3c0000 ... 0x3d3ffe: + case 0x3e0000 ... 0x3e1ffe: + return true; + default: + return false; + } +} + +static bool cs47l90_16bit_readable_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_SOFTWARE_RESET: + case MADERA_HARDWARE_REVISION: + case MADERA_WRITE_SEQUENCER_CTRL_0: + case MADERA_WRITE_SEQUENCER_CTRL_1: + case MADERA_WRITE_SEQUENCER_CTRL_2: + case MADERA_TONE_GENERATOR_1: + case MADERA_TONE_GENERATOR_2: + case MADERA_TONE_GENERATOR_3: + case MADERA_TONE_GENERATOR_4: + case MADERA_TONE_GENERATOR_5: + case MADERA_PWM_DRIVE_1: + case MADERA_PWM_DRIVE_2: + case MADERA_PWM_DRIVE_3: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_1: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_2: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_3: + case MADERA_SAMPLE_RATE_SEQUENCE_SELECT_4: + case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1: + case MADERA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: + case MADERA_HAPTICS_CONTROL_1: + case MADERA_HAPTICS_CONTROL_2: + case MADERA_HAPTICS_PHASE_1_INTENSITY: + case MADERA_HAPTICS_PHASE_1_DURATION: + case MADERA_HAPTICS_PHASE_2_INTENSITY: + case MADERA_HAPTICS_PHASE_2_DURATION: + case MADERA_HAPTICS_PHASE_3_INTENSITY: + case MADERA_HAPTICS_PHASE_3_DURATION: + case MADERA_HAPTICS_STATUS: + case MADERA_COMFORT_NOISE_GENERATOR: + case MADERA_CLOCK_32K_1: + case MADERA_SYSTEM_CLOCK_1: + case MADERA_SAMPLE_RATE_1: + case MADERA_SAMPLE_RATE_2: + case MADERA_SAMPLE_RATE_3: + case MADERA_SAMPLE_RATE_1_STATUS: + case MADERA_SAMPLE_RATE_2_STATUS: + case MADERA_SAMPLE_RATE_3_STATUS: + case MADERA_ASYNC_CLOCK_1: + case MADERA_ASYNC_SAMPLE_RATE_1: + case MADERA_ASYNC_SAMPLE_RATE_1_STATUS: + case MADERA_ASYNC_SAMPLE_RATE_2: + case MADERA_ASYNC_SAMPLE_RATE_2_STATUS: + case MADERA_DSP_CLOCK_1: + case MADERA_DSP_CLOCK_2: + case MADERA_OUTPUT_SYSTEM_CLOCK: + case MADERA_OUTPUT_ASYNC_CLOCK: + case MADERA_RATE_ESTIMATOR_1: + case MADERA_RATE_ESTIMATOR_2: + case MADERA_RATE_ESTIMATOR_3: + case MADERA_RATE_ESTIMATOR_4: + case MADERA_RATE_ESTIMATOR_5: + case MADERA_FLL1_CONTROL_1: + case MADERA_FLL1_CONTROL_2: + case MADERA_FLL1_CONTROL_3: + case MADERA_FLL1_CONTROL_4: + case MADERA_FLL1_CONTROL_5: + case MADERA_FLL1_CONTROL_6: + case MADERA_FLL1_CONTROL_7: + case MADERA_FLL1_EFS_2: + case MADERA_FLL1_LOOP_FILTER_TEST_1: + case MADERA_FLL1_SYNCHRONISER_1: + case MADERA_FLL1_SYNCHRONISER_2: + case MADERA_FLL1_SYNCHRONISER_3: + case MADERA_FLL1_SYNCHRONISER_4: + case MADERA_FLL1_SYNCHRONISER_5: + case MADERA_FLL1_SYNCHRONISER_6: + case MADERA_FLL1_SYNCHRONISER_7: + case MADERA_FLL1_SPREAD_SPECTRUM: + case MADERA_FLL1_GPIO_CLOCK: + case MADERA_FLL2_CONTROL_1: + case MADERA_FLL2_CONTROL_2: + case MADERA_FLL2_CONTROL_3: + case MADERA_FLL2_CONTROL_4: + case MADERA_FLL2_CONTROL_5: + case MADERA_FLL2_CONTROL_6: + case MADERA_FLL2_CONTROL_7: + case MADERA_FLL2_EFS_2: + case MADERA_FLL2_LOOP_FILTER_TEST_1: + case MADERA_FLL2_SYNCHRONISER_1: + case MADERA_FLL2_SYNCHRONISER_2: + case MADERA_FLL2_SYNCHRONISER_3: + case MADERA_FLL2_SYNCHRONISER_4: + case MADERA_FLL2_SYNCHRONISER_5: + case MADERA_FLL2_SYNCHRONISER_6: + case MADERA_FLL2_SYNCHRONISER_7: + case MADERA_FLL2_SPREAD_SPECTRUM: + case MADERA_FLL2_GPIO_CLOCK: + case MADERA_FLLAO_CONTROL_1: + case MADERA_FLLAO_CONTROL_2: + case MADERA_FLLAO_CONTROL_3: + case MADERA_FLLAO_CONTROL_4: + case MADERA_FLLAO_CONTROL_5: + case MADERA_FLLAO_CONTROL_6: + case MADERA_FLLAO_CONTROL_7: + case MADERA_FLLAO_CONTROL_8: + case MADERA_FLLAO_CONTROL_9: + case MADERA_FLLAO_CONTROL_10: + case MADERA_FLLAO_CONTROL_11: + case MADERA_MIC_CHARGE_PUMP_1: + case MADERA_LDO2_CONTROL_1: + case MADERA_MIC_BIAS_CTRL_1: + case MADERA_MIC_BIAS_CTRL_2: + case MADERA_MIC_BIAS_CTRL_5: + case MADERA_MIC_BIAS_CTRL_6: + case MADERA_HP_CTRL_1L: + case MADERA_HP_CTRL_1R: + case MADERA_HP_CTRL_2L: + case MADERA_HP_CTRL_2R: + case MADERA_HP_CTRL_3L: + case MADERA_HP_CTRL_3R: + case MADERA_EDRE_HP_STEREO_CONTROL: + case MADERA_ACCESSORY_DETECT_MODE_1: + case MADERA_HEADPHONE_DETECT_0: + case MADERA_HEADPHONE_DETECT_1: + case MADERA_HEADPHONE_DETECT_2: + case MADERA_HEADPHONE_DETECT_3: + case MADERA_HEADPHONE_DETECT_5: + case MADERA_MICD_CLAMP_CONTROL: + case MADERA_MIC_DETECT_1_CONTROL_0: + case MADERA_MIC_DETECT_1_CONTROL_1: + case MADERA_MIC_DETECT_1_CONTROL_2: + case MADERA_MIC_DETECT_1_CONTROL_3: + case MADERA_MIC_DETECT_1_LEVEL_1: + case MADERA_MIC_DETECT_1_LEVEL_2: + case MADERA_MIC_DETECT_1_LEVEL_3: + case MADERA_MIC_DETECT_1_LEVEL_4: + case MADERA_MIC_DETECT_1_CONTROL_4: + case MADERA_MIC_DETECT_2_CONTROL_0: + case MADERA_MIC_DETECT_2_CONTROL_1: + case MADERA_MIC_DETECT_2_CONTROL_2: + case MADERA_MIC_DETECT_2_CONTROL_3: + case MADERA_MIC_DETECT_2_LEVEL_1: + case MADERA_MIC_DETECT_2_LEVEL_2: + case MADERA_MIC_DETECT_2_LEVEL_3: + case MADERA_MIC_DETECT_2_LEVEL_4: + case MADERA_MIC_DETECT_2_CONTROL_4: + case MADERA_GP_SWITCH_1: + case MADERA_JACK_DETECT_ANALOGUE: + case MADERA_INPUT_ENABLES: + case MADERA_INPUT_ENABLES_STATUS: + case MADERA_INPUT_RATE: + case MADERA_INPUT_VOLUME_RAMP: + case MADERA_HPF_CONTROL: + case MADERA_IN1L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_1L: + case MADERA_DMIC1L_CONTROL: + case MADERA_IN1L_RATE_CONTROL: + case MADERA_IN1R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_1R: + case MADERA_DMIC1R_CONTROL: + case MADERA_IN1R_RATE_CONTROL: + case MADERA_IN2L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_2L: + case MADERA_DMIC2L_CONTROL: + case MADERA_IN2L_RATE_CONTROL: + case MADERA_IN2R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_2R: + case MADERA_DMIC2R_CONTROL: + case MADERA_IN2R_RATE_CONTROL: + case MADERA_IN3L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_3L: + case MADERA_DMIC3L_CONTROL: + case MADERA_IN3L_RATE_CONTROL: + case MADERA_IN3R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_3R: + case MADERA_DMIC3R_CONTROL: + case MADERA_IN3R_RATE_CONTROL: + case MADERA_IN4L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_4L: + case MADERA_DMIC4L_CONTROL: + case MADERA_IN4L_RATE_CONTROL: + case MADERA_IN4R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_4R: + case MADERA_DMIC4R_CONTROL: + case MADERA_IN4R_RATE_CONTROL: + case MADERA_IN5L_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_5L: + case MADERA_DMIC5L_CONTROL: + case MADERA_IN5L_RATE_CONTROL: + case MADERA_IN5R_CONTROL: + case MADERA_ADC_DIGITAL_VOLUME_5R: + case MADERA_DMIC5R_CONTROL: + case MADERA_IN5R_RATE_CONTROL: + case MADERA_OUTPUT_ENABLES_1: + case MADERA_OUTPUT_STATUS_1: + case MADERA_RAW_OUTPUT_STATUS_1: + case MADERA_OUTPUT_RATE_1: + case MADERA_OUTPUT_VOLUME_RAMP: + case MADERA_OUTPUT_PATH_CONFIG_1L: + case MADERA_DAC_DIGITAL_VOLUME_1L: + case MADERA_OUTPUT_PATH_CONFIG_1: + case MADERA_NOISE_GATE_SELECT_1L: + case MADERA_OUTPUT_PATH_CONFIG_1R: + case MADERA_DAC_DIGITAL_VOLUME_1R: + case MADERA_NOISE_GATE_SELECT_1R: + case MADERA_OUTPUT_PATH_CONFIG_2L: + case MADERA_DAC_DIGITAL_VOLUME_2L: + case MADERA_OUTPUT_PATH_CONFIG_2: + case MADERA_NOISE_GATE_SELECT_2L: + case MADERA_OUTPUT_PATH_CONFIG_2R: + case MADERA_DAC_DIGITAL_VOLUME_2R: + case MADERA_NOISE_GATE_SELECT_2R: + case MADERA_OUTPUT_PATH_CONFIG_3L: + case MADERA_DAC_DIGITAL_VOLUME_3L: + case MADERA_NOISE_GATE_SELECT_3L: + case MADERA_OUTPUT_PATH_CONFIG_3R: + case MADERA_DAC_DIGITAL_VOLUME_3R: + case MADERA_NOISE_GATE_SELECT_3R: + case MADERA_OUTPUT_PATH_CONFIG_5L: + case MADERA_DAC_DIGITAL_VOLUME_5L: + case MADERA_NOISE_GATE_SELECT_5L: + case MADERA_OUTPUT_PATH_CONFIG_5R: + case MADERA_DAC_DIGITAL_VOLUME_5R: + case MADERA_NOISE_GATE_SELECT_5R: + case MADERA_DRE_ENABLE: + case MADERA_EDRE_ENABLE: + case MADERA_DAC_AEC_CONTROL_1: + case MADERA_NOISE_GATE_CONTROL: + case MADERA_PDM_SPK1_CTRL_1: + case MADERA_PDM_SPK1_CTRL_2: + case MADERA_HP1_SHORT_CIRCUIT_CTRL: + case MADERA_HP2_SHORT_CIRCUIT_CTRL: + case MADERA_HP3_SHORT_CIRCUIT_CTRL: + case MADERA_AIF1_BCLK_CTRL: + case MADERA_AIF1_TX_PIN_CTRL: + case MADERA_AIF1_RX_PIN_CTRL: + case MADERA_AIF1_RATE_CTRL: + case MADERA_AIF1_FORMAT: + case MADERA_AIF1_RX_BCLK_RATE: + case MADERA_AIF1_FRAME_CTRL_1: + case MADERA_AIF1_FRAME_CTRL_2: + case MADERA_AIF1_FRAME_CTRL_3: + case MADERA_AIF1_FRAME_CTRL_4: + case MADERA_AIF1_FRAME_CTRL_5: + case MADERA_AIF1_FRAME_CTRL_6: + case MADERA_AIF1_FRAME_CTRL_7: + case MADERA_AIF1_FRAME_CTRL_8: + case MADERA_AIF1_FRAME_CTRL_9: + case MADERA_AIF1_FRAME_CTRL_10: + case MADERA_AIF1_FRAME_CTRL_11: + case MADERA_AIF1_FRAME_CTRL_12: + case MADERA_AIF1_FRAME_CTRL_13: + case MADERA_AIF1_FRAME_CTRL_14: + case MADERA_AIF1_FRAME_CTRL_15: + case MADERA_AIF1_FRAME_CTRL_16: + case MADERA_AIF1_FRAME_CTRL_17: + case MADERA_AIF1_FRAME_CTRL_18: + case MADERA_AIF1_TX_ENABLES: + case MADERA_AIF1_RX_ENABLES: + case MADERA_AIF2_BCLK_CTRL: + case MADERA_AIF2_TX_PIN_CTRL: + case MADERA_AIF2_RX_PIN_CTRL: + case MADERA_AIF2_RATE_CTRL: + case MADERA_AIF2_FORMAT: + case MADERA_AIF2_RX_BCLK_RATE: + case MADERA_AIF2_FRAME_CTRL_1: + case MADERA_AIF2_FRAME_CTRL_2: + case MADERA_AIF2_FRAME_CTRL_3: + case MADERA_AIF2_FRAME_CTRL_4: + case MADERA_AIF2_FRAME_CTRL_5: + case MADERA_AIF2_FRAME_CTRL_6: + case MADERA_AIF2_FRAME_CTRL_7: + case MADERA_AIF2_FRAME_CTRL_8: + case MADERA_AIF2_FRAME_CTRL_9: + case MADERA_AIF2_FRAME_CTRL_10: + case MADERA_AIF2_FRAME_CTRL_11: + case MADERA_AIF2_FRAME_CTRL_12: + case MADERA_AIF2_FRAME_CTRL_13: + case MADERA_AIF2_FRAME_CTRL_14: + case MADERA_AIF2_FRAME_CTRL_15: + case MADERA_AIF2_FRAME_CTRL_16: + case MADERA_AIF2_FRAME_CTRL_17: + case MADERA_AIF2_FRAME_CTRL_18: + case MADERA_AIF2_TX_ENABLES: + case MADERA_AIF2_RX_ENABLES: + case MADERA_AIF3_BCLK_CTRL: + case MADERA_AIF3_TX_PIN_CTRL: + case MADERA_AIF3_RX_PIN_CTRL: + case MADERA_AIF3_RATE_CTRL: + case MADERA_AIF3_FORMAT: + case MADERA_AIF3_RX_BCLK_RATE: + case MADERA_AIF3_FRAME_CTRL_1: + case MADERA_AIF3_FRAME_CTRL_2: + case MADERA_AIF3_FRAME_CTRL_3: + case MADERA_AIF3_FRAME_CTRL_4: + case MADERA_AIF3_FRAME_CTRL_11: + case MADERA_AIF3_FRAME_CTRL_12: + case MADERA_AIF3_TX_ENABLES: + case MADERA_AIF3_RX_ENABLES: + case MADERA_AIF4_BCLK_CTRL: + case MADERA_AIF4_TX_PIN_CTRL: + case MADERA_AIF4_RX_PIN_CTRL: + case MADERA_AIF4_RATE_CTRL: + case MADERA_AIF4_FORMAT: + case MADERA_AIF4_RX_BCLK_RATE: + case MADERA_AIF4_FRAME_CTRL_1: + case MADERA_AIF4_FRAME_CTRL_2: + case MADERA_AIF4_FRAME_CTRL_3: + case MADERA_AIF4_FRAME_CTRL_4: + case MADERA_AIF4_FRAME_CTRL_11: + case MADERA_AIF4_FRAME_CTRL_12: + case MADERA_AIF4_TX_ENABLES: + case MADERA_AIF4_RX_ENABLES: + case MADERA_SPD1_TX_CONTROL: + case MADERA_SPD1_TX_CHANNEL_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_2: + case MADERA_SPD1_TX_CHANNEL_STATUS_3: + case MADERA_SLIMBUS_FRAMER_REF_GEAR: + case MADERA_SLIMBUS_RATES_1: + case MADERA_SLIMBUS_RATES_2: + case MADERA_SLIMBUS_RATES_3: + case MADERA_SLIMBUS_RATES_4: + case MADERA_SLIMBUS_RATES_5: + case MADERA_SLIMBUS_RATES_6: + case MADERA_SLIMBUS_RATES_7: + case MADERA_SLIMBUS_RATES_8: + case MADERA_SLIMBUS_RX_CHANNEL_ENABLE: + case MADERA_SLIMBUS_TX_CHANNEL_ENABLE: + case MADERA_SLIMBUS_RX_PORT_STATUS: + case MADERA_SLIMBUS_TX_PORT_STATUS: + case MADERA_PWM1MIX_INPUT_1_SOURCE: + case MADERA_PWM1MIX_INPUT_1_VOLUME: + case MADERA_PWM1MIX_INPUT_2_SOURCE: + case MADERA_PWM1MIX_INPUT_2_VOLUME: + case MADERA_PWM1MIX_INPUT_3_SOURCE: + case MADERA_PWM1MIX_INPUT_3_VOLUME: + case MADERA_PWM1MIX_INPUT_4_SOURCE: + case MADERA_PWM1MIX_INPUT_4_VOLUME: + case MADERA_PWM2MIX_INPUT_1_SOURCE: + case MADERA_PWM2MIX_INPUT_1_VOLUME: + case MADERA_PWM2MIX_INPUT_2_SOURCE: + case MADERA_PWM2MIX_INPUT_2_VOLUME: + case MADERA_PWM2MIX_INPUT_3_SOURCE: + case MADERA_PWM2MIX_INPUT_3_VOLUME: + case MADERA_PWM2MIX_INPUT_4_SOURCE: + case MADERA_PWM2MIX_INPUT_4_VOLUME: + case MADERA_OUT1LMIX_INPUT_1_SOURCE: + case MADERA_OUT1LMIX_INPUT_1_VOLUME: + case MADERA_OUT1LMIX_INPUT_2_SOURCE: + case MADERA_OUT1LMIX_INPUT_2_VOLUME: + case MADERA_OUT1LMIX_INPUT_3_SOURCE: + case MADERA_OUT1LMIX_INPUT_3_VOLUME: + case MADERA_OUT1LMIX_INPUT_4_SOURCE: + case MADERA_OUT1LMIX_INPUT_4_VOLUME: + case MADERA_OUT1RMIX_INPUT_1_SOURCE: + case MADERA_OUT1RMIX_INPUT_1_VOLUME: + case MADERA_OUT1RMIX_INPUT_2_SOURCE: + case MADERA_OUT1RMIX_INPUT_2_VOLUME: + case MADERA_OUT1RMIX_INPUT_3_SOURCE: + case MADERA_OUT1RMIX_INPUT_3_VOLUME: + case MADERA_OUT1RMIX_INPUT_4_SOURCE: + case MADERA_OUT1RMIX_INPUT_4_VOLUME: + case MADERA_OUT2LMIX_INPUT_1_SOURCE: + case MADERA_OUT2LMIX_INPUT_1_VOLUME: + case MADERA_OUT2LMIX_INPUT_2_SOURCE: + case MADERA_OUT2LMIX_INPUT_2_VOLUME: + case MADERA_OUT2LMIX_INPUT_3_SOURCE: + case MADERA_OUT2LMIX_INPUT_3_VOLUME: + case MADERA_OUT2LMIX_INPUT_4_SOURCE: + case MADERA_OUT2LMIX_INPUT_4_VOLUME: + case MADERA_OUT2RMIX_INPUT_1_SOURCE: + case MADERA_OUT2RMIX_INPUT_1_VOLUME: + case MADERA_OUT2RMIX_INPUT_2_SOURCE: + case MADERA_OUT2RMIX_INPUT_2_VOLUME: + case MADERA_OUT2RMIX_INPUT_3_SOURCE: + case MADERA_OUT2RMIX_INPUT_3_VOLUME: + case MADERA_OUT2RMIX_INPUT_4_SOURCE: + case MADERA_OUT2RMIX_INPUT_4_VOLUME: + case MADERA_OUT3LMIX_INPUT_1_SOURCE: + case MADERA_OUT3LMIX_INPUT_1_VOLUME: + case MADERA_OUT3LMIX_INPUT_2_SOURCE: + case MADERA_OUT3LMIX_INPUT_2_VOLUME: + case MADERA_OUT3LMIX_INPUT_3_SOURCE: + case MADERA_OUT3LMIX_INPUT_3_VOLUME: + case MADERA_OUT3LMIX_INPUT_4_SOURCE: + case MADERA_OUT3LMIX_INPUT_4_VOLUME: + case MADERA_OUT3RMIX_INPUT_1_SOURCE: + case MADERA_OUT3RMIX_INPUT_1_VOLUME: + case MADERA_OUT3RMIX_INPUT_2_SOURCE: + case MADERA_OUT3RMIX_INPUT_2_VOLUME: + case MADERA_OUT3RMIX_INPUT_3_SOURCE: + case MADERA_OUT3RMIX_INPUT_3_VOLUME: + case MADERA_OUT3RMIX_INPUT_4_SOURCE: + case MADERA_OUT3RMIX_INPUT_4_VOLUME: + case MADERA_OUT5LMIX_INPUT_1_SOURCE: + case MADERA_OUT5LMIX_INPUT_1_VOLUME: + case MADERA_OUT5LMIX_INPUT_2_SOURCE: + case MADERA_OUT5LMIX_INPUT_2_VOLUME: + case MADERA_OUT5LMIX_INPUT_3_SOURCE: + case MADERA_OUT5LMIX_INPUT_3_VOLUME: + case MADERA_OUT5LMIX_INPUT_4_SOURCE: + case MADERA_OUT5LMIX_INPUT_4_VOLUME: + case MADERA_OUT5RMIX_INPUT_1_SOURCE: + case MADERA_OUT5RMIX_INPUT_1_VOLUME: + case MADERA_OUT5RMIX_INPUT_2_SOURCE: + case MADERA_OUT5RMIX_INPUT_2_VOLUME: + case MADERA_OUT5RMIX_INPUT_3_SOURCE: + case MADERA_OUT5RMIX_INPUT_3_VOLUME: + case MADERA_OUT5RMIX_INPUT_4_SOURCE: + case MADERA_OUT5RMIX_INPUT_4_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX3MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX3MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX4MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX4MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX5MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX5MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX6MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX6MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX7MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX7MIX_INPUT_4_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_1_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_1_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_2_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_2_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_3_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_3_VOLUME: + case MADERA_AIF1TX8MIX_INPUT_4_SOURCE: + case MADERA_AIF1TX8MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX3MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX3MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX4MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX4MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX5MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX5MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX6MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX6MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX7MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX7MIX_INPUT_4_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_1_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_1_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_2_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_2_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_3_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_3_VOLUME: + case MADERA_AIF2TX8MIX_INPUT_4_SOURCE: + case MADERA_AIF2TX8MIX_INPUT_4_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF3TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF3TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF3TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF3TX2MIX_INPUT_4_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_1_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_1_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_2_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_2_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_3_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_3_VOLUME: + case MADERA_AIF4TX1MIX_INPUT_4_SOURCE: + case MADERA_AIF4TX1MIX_INPUT_4_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_1_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_1_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_2_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_2_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_3_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_3_VOLUME: + case MADERA_AIF4TX2MIX_INPUT_4_SOURCE: + case MADERA_AIF4TX2MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX1MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX1MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX2MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX2MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX3MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX3MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX4MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX4MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX5MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX5MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX6MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX6MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX7MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX7MIX_INPUT_4_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_1_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_1_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_2_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_2_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_3_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_3_VOLUME: + case MADERA_SLIMTX8MIX_INPUT_4_SOURCE: + case MADERA_SLIMTX8MIX_INPUT_4_VOLUME: + case MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE: + case MADERA_SPDIF1TX1MIX_INPUT_1_VOLUME: + case MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE: + case MADERA_SPDIF1TX2MIX_INPUT_1_VOLUME: + case MADERA_EQ1MIX_INPUT_1_SOURCE: + case MADERA_EQ1MIX_INPUT_1_VOLUME: + case MADERA_EQ1MIX_INPUT_2_SOURCE: + case MADERA_EQ1MIX_INPUT_2_VOLUME: + case MADERA_EQ1MIX_INPUT_3_SOURCE: + case MADERA_EQ1MIX_INPUT_3_VOLUME: + case MADERA_EQ1MIX_INPUT_4_SOURCE: + case MADERA_EQ1MIX_INPUT_4_VOLUME: + case MADERA_EQ2MIX_INPUT_1_SOURCE: + case MADERA_EQ2MIX_INPUT_1_VOLUME: + case MADERA_EQ2MIX_INPUT_2_SOURCE: + case MADERA_EQ2MIX_INPUT_2_VOLUME: + case MADERA_EQ2MIX_INPUT_3_SOURCE: + case MADERA_EQ2MIX_INPUT_3_VOLUME: + case MADERA_EQ2MIX_INPUT_4_SOURCE: + case MADERA_EQ2MIX_INPUT_4_VOLUME: + case MADERA_EQ3MIX_INPUT_1_SOURCE: + case MADERA_EQ3MIX_INPUT_1_VOLUME: + case MADERA_EQ3MIX_INPUT_2_SOURCE: + case MADERA_EQ3MIX_INPUT_2_VOLUME: + case MADERA_EQ3MIX_INPUT_3_SOURCE: + case MADERA_EQ3MIX_INPUT_3_VOLUME: + case MADERA_EQ3MIX_INPUT_4_SOURCE: + case MADERA_EQ3MIX_INPUT_4_VOLUME: + case MADERA_EQ4MIX_INPUT_1_SOURCE: + case MADERA_EQ4MIX_INPUT_1_VOLUME: + case MADERA_EQ4MIX_INPUT_2_SOURCE: + case MADERA_EQ4MIX_INPUT_2_VOLUME: + case MADERA_EQ4MIX_INPUT_3_SOURCE: + case MADERA_EQ4MIX_INPUT_3_VOLUME: + case MADERA_EQ4MIX_INPUT_4_SOURCE: + case MADERA_EQ4MIX_INPUT_4_VOLUME: + case MADERA_DRC1LMIX_INPUT_1_SOURCE: + case MADERA_DRC1LMIX_INPUT_1_VOLUME: + case MADERA_DRC1LMIX_INPUT_2_SOURCE: + case MADERA_DRC1LMIX_INPUT_2_VOLUME: + case MADERA_DRC1LMIX_INPUT_3_SOURCE: + case MADERA_DRC1LMIX_INPUT_3_VOLUME: + case MADERA_DRC1LMIX_INPUT_4_SOURCE: + case MADERA_DRC1LMIX_INPUT_4_VOLUME: + case MADERA_DRC1RMIX_INPUT_1_SOURCE: + case MADERA_DRC1RMIX_INPUT_1_VOLUME: + case MADERA_DRC1RMIX_INPUT_2_SOURCE: + case MADERA_DRC1RMIX_INPUT_2_VOLUME: + case MADERA_DRC1RMIX_INPUT_3_SOURCE: + case MADERA_DRC1RMIX_INPUT_3_VOLUME: + case MADERA_DRC1RMIX_INPUT_4_SOURCE: + case MADERA_DRC1RMIX_INPUT_4_VOLUME: + case MADERA_DRC2LMIX_INPUT_1_SOURCE: + case MADERA_DRC2LMIX_INPUT_1_VOLUME: + case MADERA_DRC2LMIX_INPUT_2_SOURCE: + case MADERA_DRC2LMIX_INPUT_2_VOLUME: + case MADERA_DRC2LMIX_INPUT_3_SOURCE: + case MADERA_DRC2LMIX_INPUT_3_VOLUME: + case MADERA_DRC2LMIX_INPUT_4_SOURCE: + case MADERA_DRC2LMIX_INPUT_4_VOLUME: + case MADERA_DRC2RMIX_INPUT_1_SOURCE: + case MADERA_DRC2RMIX_INPUT_1_VOLUME: + case MADERA_DRC2RMIX_INPUT_2_SOURCE: + case MADERA_DRC2RMIX_INPUT_2_VOLUME: + case MADERA_DRC2RMIX_INPUT_3_SOURCE: + case MADERA_DRC2RMIX_INPUT_3_VOLUME: + case MADERA_DRC2RMIX_INPUT_4_SOURCE: + case MADERA_DRC2RMIX_INPUT_4_VOLUME: + case MADERA_HPLP1MIX_INPUT_1_SOURCE: + case MADERA_HPLP1MIX_INPUT_1_VOLUME: + case MADERA_HPLP1MIX_INPUT_2_SOURCE: + case MADERA_HPLP1MIX_INPUT_2_VOLUME: + case MADERA_HPLP1MIX_INPUT_3_SOURCE: + case MADERA_HPLP1MIX_INPUT_3_VOLUME: + case MADERA_HPLP1MIX_INPUT_4_SOURCE: + case MADERA_HPLP1MIX_INPUT_4_VOLUME: + case MADERA_HPLP2MIX_INPUT_1_SOURCE: + case MADERA_HPLP2MIX_INPUT_1_VOLUME: + case MADERA_HPLP2MIX_INPUT_2_SOURCE: + case MADERA_HPLP2MIX_INPUT_2_VOLUME: + case MADERA_HPLP2MIX_INPUT_3_SOURCE: + case MADERA_HPLP2MIX_INPUT_3_VOLUME: + case MADERA_HPLP2MIX_INPUT_4_SOURCE: + case MADERA_HPLP2MIX_INPUT_4_VOLUME: + case MADERA_HPLP3MIX_INPUT_1_SOURCE: + case MADERA_HPLP3MIX_INPUT_1_VOLUME: + case MADERA_HPLP3MIX_INPUT_2_SOURCE: + case MADERA_HPLP3MIX_INPUT_2_VOLUME: + case MADERA_HPLP3MIX_INPUT_3_SOURCE: + case MADERA_HPLP3MIX_INPUT_3_VOLUME: + case MADERA_HPLP3MIX_INPUT_4_SOURCE: + case MADERA_HPLP3MIX_INPUT_4_VOLUME: + case MADERA_HPLP4MIX_INPUT_1_SOURCE: + case MADERA_HPLP4MIX_INPUT_1_VOLUME: + case MADERA_HPLP4MIX_INPUT_2_SOURCE: + case MADERA_HPLP4MIX_INPUT_2_VOLUME: + case MADERA_HPLP4MIX_INPUT_3_SOURCE: + case MADERA_HPLP4MIX_INPUT_3_VOLUME: + case MADERA_HPLP4MIX_INPUT_4_SOURCE: + case MADERA_HPLP4MIX_INPUT_4_VOLUME: + case MADERA_DSP1LMIX_INPUT_1_SOURCE: + case MADERA_DSP1LMIX_INPUT_1_VOLUME: + case MADERA_DSP1LMIX_INPUT_2_SOURCE: + case MADERA_DSP1LMIX_INPUT_2_VOLUME: + case MADERA_DSP1LMIX_INPUT_3_SOURCE: + case MADERA_DSP1LMIX_INPUT_3_VOLUME: + case MADERA_DSP1LMIX_INPUT_4_SOURCE: + case MADERA_DSP1LMIX_INPUT_4_VOLUME: + case MADERA_DSP1RMIX_INPUT_1_SOURCE: + case MADERA_DSP1RMIX_INPUT_1_VOLUME: + case MADERA_DSP1RMIX_INPUT_2_SOURCE: + case MADERA_DSP1RMIX_INPUT_2_VOLUME: + case MADERA_DSP1RMIX_INPUT_3_SOURCE: + case MADERA_DSP1RMIX_INPUT_3_VOLUME: + case MADERA_DSP1RMIX_INPUT_4_SOURCE: + case MADERA_DSP1RMIX_INPUT_4_VOLUME: + case MADERA_DSP1AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP1AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP2LMIX_INPUT_1_SOURCE: + case MADERA_DSP2LMIX_INPUT_1_VOLUME: + case MADERA_DSP2LMIX_INPUT_2_SOURCE: + case MADERA_DSP2LMIX_INPUT_2_VOLUME: + case MADERA_DSP2LMIX_INPUT_3_SOURCE: + case MADERA_DSP2LMIX_INPUT_3_VOLUME: + case MADERA_DSP2LMIX_INPUT_4_SOURCE: + case MADERA_DSP2LMIX_INPUT_4_VOLUME: + case MADERA_DSP2RMIX_INPUT_1_SOURCE: + case MADERA_DSP2RMIX_INPUT_1_VOLUME: + case MADERA_DSP2RMIX_INPUT_2_SOURCE: + case MADERA_DSP2RMIX_INPUT_2_VOLUME: + case MADERA_DSP2RMIX_INPUT_3_SOURCE: + case MADERA_DSP2RMIX_INPUT_3_VOLUME: + case MADERA_DSP2RMIX_INPUT_4_SOURCE: + case MADERA_DSP2RMIX_INPUT_4_VOLUME: + case MADERA_DSP2AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP2AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP3LMIX_INPUT_1_SOURCE: + case MADERA_DSP3LMIX_INPUT_1_VOLUME: + case MADERA_DSP3LMIX_INPUT_2_SOURCE: + case MADERA_DSP3LMIX_INPUT_2_VOLUME: + case MADERA_DSP3LMIX_INPUT_3_SOURCE: + case MADERA_DSP3LMIX_INPUT_3_VOLUME: + case MADERA_DSP3LMIX_INPUT_4_SOURCE: + case MADERA_DSP3LMIX_INPUT_4_VOLUME: + case MADERA_DSP3RMIX_INPUT_1_SOURCE: + case MADERA_DSP3RMIX_INPUT_1_VOLUME: + case MADERA_DSP3RMIX_INPUT_2_SOURCE: + case MADERA_DSP3RMIX_INPUT_2_VOLUME: + case MADERA_DSP3RMIX_INPUT_3_SOURCE: + case MADERA_DSP3RMIX_INPUT_3_VOLUME: + case MADERA_DSP3RMIX_INPUT_4_SOURCE: + case MADERA_DSP3RMIX_INPUT_4_VOLUME: + case MADERA_DSP3AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP3AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP4LMIX_INPUT_1_SOURCE: + case MADERA_DSP4LMIX_INPUT_1_VOLUME: + case MADERA_DSP4LMIX_INPUT_2_SOURCE: + case MADERA_DSP4LMIX_INPUT_2_VOLUME: + case MADERA_DSP4LMIX_INPUT_3_SOURCE: + case MADERA_DSP4LMIX_INPUT_3_VOLUME: + case MADERA_DSP4LMIX_INPUT_4_SOURCE: + case MADERA_DSP4LMIX_INPUT_4_VOLUME: + case MADERA_DSP4RMIX_INPUT_1_SOURCE: + case MADERA_DSP4RMIX_INPUT_1_VOLUME: + case MADERA_DSP4RMIX_INPUT_2_SOURCE: + case MADERA_DSP4RMIX_INPUT_2_VOLUME: + case MADERA_DSP4RMIX_INPUT_3_SOURCE: + case MADERA_DSP4RMIX_INPUT_3_VOLUME: + case MADERA_DSP4RMIX_INPUT_4_SOURCE: + case MADERA_DSP4RMIX_INPUT_4_VOLUME: + case MADERA_DSP4AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP4AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP5LMIX_INPUT_1_SOURCE: + case MADERA_DSP5LMIX_INPUT_1_VOLUME: + case MADERA_DSP5LMIX_INPUT_2_SOURCE: + case MADERA_DSP5LMIX_INPUT_2_VOLUME: + case MADERA_DSP5LMIX_INPUT_3_SOURCE: + case MADERA_DSP5LMIX_INPUT_3_VOLUME: + case MADERA_DSP5LMIX_INPUT_4_SOURCE: + case MADERA_DSP5LMIX_INPUT_4_VOLUME: + case MADERA_DSP5RMIX_INPUT_1_SOURCE: + case MADERA_DSP5RMIX_INPUT_1_VOLUME: + case MADERA_DSP5RMIX_INPUT_2_SOURCE: + case MADERA_DSP5RMIX_INPUT_2_VOLUME: + case MADERA_DSP5RMIX_INPUT_3_SOURCE: + case MADERA_DSP5RMIX_INPUT_3_VOLUME: + case MADERA_DSP5RMIX_INPUT_4_SOURCE: + case MADERA_DSP5RMIX_INPUT_4_VOLUME: + case MADERA_DSP5AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP5AUX6MIX_INPUT_1_SOURCE: + case MADERA_ASRC1_1LMIX_INPUT_1_SOURCE: + case MADERA_ASRC1_1RMIX_INPUT_1_SOURCE: + case MADERA_ASRC1_2LMIX_INPUT_1_SOURCE: + case MADERA_ASRC1_2RMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_1LMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_1RMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_2LMIX_INPUT_1_SOURCE: + case MADERA_ASRC2_2RMIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC3MIX_INPUT_1_SOURCE: + case MADERA_ISRC1DEC4MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT3MIX_INPUT_1_SOURCE: + case MADERA_ISRC1INT4MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC3MIX_INPUT_1_SOURCE: + case MADERA_ISRC2DEC4MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT3MIX_INPUT_1_SOURCE: + case MADERA_ISRC2INT4MIX_INPUT_1_SOURCE: + case MADERA_ISRC3DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC3DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC3INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC3INT2MIX_INPUT_1_SOURCE: + case MADERA_ISRC4DEC1MIX_INPUT_1_SOURCE: + case MADERA_ISRC4DEC2MIX_INPUT_1_SOURCE: + case MADERA_ISRC4INT1MIX_INPUT_1_SOURCE: + case MADERA_ISRC4INT2MIX_INPUT_1_SOURCE: + case MADERA_DSP6LMIX_INPUT_1_SOURCE: + case MADERA_DSP6LMIX_INPUT_1_VOLUME: + case MADERA_DSP6LMIX_INPUT_2_SOURCE: + case MADERA_DSP6LMIX_INPUT_2_VOLUME: + case MADERA_DSP6LMIX_INPUT_3_SOURCE: + case MADERA_DSP6LMIX_INPUT_3_VOLUME: + case MADERA_DSP6LMIX_INPUT_4_SOURCE: + case MADERA_DSP6LMIX_INPUT_4_VOLUME: + case MADERA_DSP6RMIX_INPUT_1_SOURCE: + case MADERA_DSP6RMIX_INPUT_1_VOLUME: + case MADERA_DSP6RMIX_INPUT_2_SOURCE: + case MADERA_DSP6RMIX_INPUT_2_VOLUME: + case MADERA_DSP6RMIX_INPUT_3_SOURCE: + case MADERA_DSP6RMIX_INPUT_3_VOLUME: + case MADERA_DSP6RMIX_INPUT_4_SOURCE: + case MADERA_DSP6RMIX_INPUT_4_VOLUME: + case MADERA_DSP6AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP6AUX6MIX_INPUT_1_SOURCE: + case MADERA_DSP7LMIX_INPUT_1_SOURCE: + case MADERA_DSP7LMIX_INPUT_1_VOLUME: + case MADERA_DSP7LMIX_INPUT_2_SOURCE: + case MADERA_DSP7LMIX_INPUT_2_VOLUME: + case MADERA_DSP7LMIX_INPUT_3_SOURCE: + case MADERA_DSP7LMIX_INPUT_3_VOLUME: + case MADERA_DSP7LMIX_INPUT_4_SOURCE: + case MADERA_DSP7LMIX_INPUT_4_VOLUME: + case MADERA_DSP7RMIX_INPUT_1_SOURCE: + case MADERA_DSP7RMIX_INPUT_1_VOLUME: + case MADERA_DSP7RMIX_INPUT_2_SOURCE: + case MADERA_DSP7RMIX_INPUT_2_VOLUME: + case MADERA_DSP7RMIX_INPUT_3_SOURCE: + case MADERA_DSP7RMIX_INPUT_3_VOLUME: + case MADERA_DSP7RMIX_INPUT_4_SOURCE: + case MADERA_DSP7RMIX_INPUT_4_VOLUME: + case MADERA_DSP7AUX1MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX2MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX3MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX4MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX5MIX_INPUT_1_SOURCE: + case MADERA_DSP7AUX6MIX_INPUT_1_SOURCE: + case MADERA_DFC1MIX_INPUT_1_SOURCE: + case MADERA_DFC2MIX_INPUT_1_SOURCE: + case MADERA_DFC3MIX_INPUT_1_SOURCE: + case MADERA_DFC4MIX_INPUT_1_SOURCE: + case MADERA_DFC5MIX_INPUT_1_SOURCE: + case MADERA_DFC6MIX_INPUT_1_SOURCE: + case MADERA_DFC7MIX_INPUT_1_SOURCE: + case MADERA_DFC8MIX_INPUT_1_SOURCE: + case MADERA_FX_CTRL1: + case MADERA_FX_CTRL2: + case MADERA_EQ1_1 ... MADERA_EQ1_21: + case MADERA_EQ2_1 ... MADERA_EQ2_21: + case MADERA_EQ3_1 ... MADERA_EQ3_21: + case MADERA_EQ4_1 ... MADERA_EQ4_21: + case MADERA_DRC1_CTRL1: + case MADERA_DRC1_CTRL2: + case MADERA_DRC1_CTRL3: + case MADERA_DRC1_CTRL4: + case MADERA_DRC1_CTRL5: + case MADERA_DRC2_CTRL1: + case MADERA_DRC2_CTRL2: + case MADERA_DRC2_CTRL3: + case MADERA_DRC2_CTRL4: + case MADERA_DRC2_CTRL5: + case MADERA_HPLPF1_1: + case MADERA_HPLPF1_2: + case MADERA_HPLPF2_1: + case MADERA_HPLPF2_2: + case MADERA_HPLPF3_1: + case MADERA_HPLPF3_2: + case MADERA_HPLPF4_1: + case MADERA_HPLPF4_2: + case MADERA_ASRC1_ENABLE: + case MADERA_ASRC1_STATUS: + case MADERA_ASRC1_RATE1: + case MADERA_ASRC1_RATE2: + case MADERA_ASRC2_ENABLE: + case MADERA_ASRC2_STATUS: + case MADERA_ASRC2_RATE1: + case MADERA_ASRC2_RATE2: + case MADERA_ISRC_1_CTRL_1: + case MADERA_ISRC_1_CTRL_2: + case MADERA_ISRC_1_CTRL_3: + case MADERA_ISRC_2_CTRL_1: + case MADERA_ISRC_2_CTRL_2: + case MADERA_ISRC_2_CTRL_3: + case MADERA_ISRC_3_CTRL_1: + case MADERA_ISRC_3_CTRL_2: + case MADERA_ISRC_3_CTRL_3: + case MADERA_ISRC_4_CTRL_1: + case MADERA_ISRC_4_CTRL_2: + case MADERA_ISRC_4_CTRL_3: + case MADERA_CLOCK_CONTROL: + case MADERA_ANC_SRC: + case MADERA_DSP_STATUS: + case MADERA_ANC_COEFF_START ... MADERA_ANC_COEFF_END: + case MADERA_FCL_FILTER_CONTROL: + case MADERA_FCL_ADC_REFORMATTER_CONTROL: + case MADERA_FCL_COEFF_START ... MADERA_FCL_COEFF_END: + case MADERA_FCR_FILTER_CONTROL: + case MADERA_FCR_ADC_REFORMATTER_CONTROL: + case MADERA_FCR_COEFF_START ... MADERA_FCR_COEFF_END: + case MADERA_DAC_COMP_1: + case MADERA_DAC_COMP_2: + case MADERA_FRF_COEFFICIENT_1L_1: + case MADERA_FRF_COEFFICIENT_1L_2: + case MADERA_FRF_COEFFICIENT_1L_3: + case MADERA_FRF_COEFFICIENT_1L_4: + case MADERA_FRF_COEFFICIENT_1R_1: + case MADERA_FRF_COEFFICIENT_1R_2: + case MADERA_FRF_COEFFICIENT_1R_3: + case MADERA_FRF_COEFFICIENT_1R_4: + case MADERA_FRF_COEFFICIENT_2L_1: + case MADERA_FRF_COEFFICIENT_2L_2: + case MADERA_FRF_COEFFICIENT_2L_3: + case MADERA_FRF_COEFFICIENT_2L_4: + case MADERA_FRF_COEFFICIENT_2R_1: + case MADERA_FRF_COEFFICIENT_2R_2: + case MADERA_FRF_COEFFICIENT_2R_3: + case MADERA_FRF_COEFFICIENT_2R_4: + case MADERA_FRF_COEFFICIENT_3L_1: + case MADERA_FRF_COEFFICIENT_3L_2: + case MADERA_FRF_COEFFICIENT_3L_3: + case MADERA_FRF_COEFFICIENT_3L_4: + case MADERA_FRF_COEFFICIENT_3R_1: + case MADERA_FRF_COEFFICIENT_3R_2: + case MADERA_FRF_COEFFICIENT_3R_3: + case MADERA_FRF_COEFFICIENT_3R_4: + case MADERA_FRF_COEFFICIENT_5L_1: + case MADERA_FRF_COEFFICIENT_5L_2: + case MADERA_FRF_COEFFICIENT_5L_3: + case MADERA_FRF_COEFFICIENT_5L_4: + case MADERA_FRF_COEFFICIENT_5R_1: + case MADERA_FRF_COEFFICIENT_5R_2: + case MADERA_FRF_COEFFICIENT_5R_3: + case MADERA_FRF_COEFFICIENT_5R_4: + case MADERA_DFC1_CTRL: + case MADERA_DFC1_RX: + case MADERA_DFC1_TX: + case MADERA_DFC2_CTRL: + case MADERA_DFC2_RX: + case MADERA_DFC2_TX: + case MADERA_DFC3_CTRL: + case MADERA_DFC3_RX: + case MADERA_DFC3_TX: + case MADERA_DFC4_CTRL: + case MADERA_DFC4_RX: + case MADERA_DFC4_TX: + case MADERA_DFC5_CTRL: + case MADERA_DFC5_RX: + case MADERA_DFC5_TX: + case MADERA_DFC6_CTRL: + case MADERA_DFC6_RX: + case MADERA_DFC6_TX: + case MADERA_DFC7_CTRL: + case MADERA_DFC7_RX: + case MADERA_DFC7_TX: + case MADERA_DFC8_CTRL: + case MADERA_DFC8_RX: + case MADERA_DFC8_TX: + case MADERA_DFC_STATUS: + case MADERA_GPIO1_CTRL_1 ... MADERA_GPIO38_CTRL_2: + case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33: + case MADERA_IRQ1_MASK_1 ... MADERA_IRQ1_MASK_33: + case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33: + case MADERA_INTERRUPT_DEBOUNCE_7: + case MADERA_IRQ1_CTRL: + return true; + default: + return false; + } +} + +static bool cs47l90_16bit_volatile_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_SOFTWARE_RESET: + case MADERA_HARDWARE_REVISION: + case MADERA_WRITE_SEQUENCER_CTRL_0: + case MADERA_WRITE_SEQUENCER_CTRL_1: + case MADERA_WRITE_SEQUENCER_CTRL_2: + case MADERA_HAPTICS_STATUS: + case MADERA_SAMPLE_RATE_1_STATUS: + case MADERA_SAMPLE_RATE_2_STATUS: + case MADERA_SAMPLE_RATE_3_STATUS: + case MADERA_ASYNC_SAMPLE_RATE_1_STATUS: + case MADERA_ASYNC_SAMPLE_RATE_2_STATUS: + case MADERA_HP_CTRL_1L: + case MADERA_HP_CTRL_1R: + case MADERA_HP_CTRL_2L: + case MADERA_HP_CTRL_2R: + case MADERA_HP_CTRL_3L: + case MADERA_HP_CTRL_3R: + case MADERA_MIC_DETECT_1_CONTROL_3: + case MADERA_MIC_DETECT_1_CONTROL_4: + case MADERA_MIC_DETECT_2_CONTROL_3: + case MADERA_MIC_DETECT_2_CONTROL_4: + case MADERA_HEADPHONE_DETECT_2: + case MADERA_HEADPHONE_DETECT_3: + case MADERA_HEADPHONE_DETECT_5: + case MADERA_INPUT_ENABLES_STATUS: + case MADERA_OUTPUT_STATUS_1: + case MADERA_RAW_OUTPUT_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_1: + case MADERA_SPD1_TX_CHANNEL_STATUS_2: + case MADERA_SPD1_TX_CHANNEL_STATUS_3: + case MADERA_SLIMBUS_RX_PORT_STATUS: + case MADERA_SLIMBUS_TX_PORT_STATUS: + case MADERA_FX_CTRL2: + case MADERA_ASRC2_STATUS: + case MADERA_ASRC1_STATUS: + case MADERA_CLOCK_CONTROL: + case MADERA_DFC_STATUS: + case MADERA_IRQ1_STATUS_1 ... MADERA_IRQ1_STATUS_33: + case MADERA_IRQ1_RAW_STATUS_1 ... MADERA_IRQ1_RAW_STATUS_33: + return true; + default: + return false; + } +} + +static bool cs47l90_32bit_readable_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_508: + case MADERA_OTP_HPDET_CAL_1 ... MADERA_OTP_HPDET_CAL_2: + case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP2_CONFIG_1 ... MADERA_DSP2_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP3_CONFIG_1 ... MADERA_DSP3_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP4_CONFIG_1 ... MADERA_DSP4_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP5_CONFIG_1 ... MADERA_DSP5_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP6_CONFIG_1 ... MADERA_DSP6_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP7_CONFIG_1 ... MADERA_DSP7_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + return true; + default: + return cs47l90_is_adsp_memory(reg); + } +} + +static bool cs47l90_32bit_volatile_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case MADERA_WSEQ_SEQUENCE_1 ... MADERA_WSEQ_SEQUENCE_508: + case MADERA_OTP_HPDET_CAL_1 ... MADERA_OTP_HPDET_CAL_2: + case MADERA_DSP1_CONFIG_1 ... MADERA_DSP1_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP2_CONFIG_1 ... MADERA_DSP2_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP3_CONFIG_1 ... MADERA_DSP3_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP4_CONFIG_1 ... MADERA_DSP4_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP5_CONFIG_1 ... MADERA_DSP5_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP6_CONFIG_1 ... MADERA_DSP6_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + case MADERA_DSP7_CONFIG_1 ... MADERA_DSP7_PMEM_ERR_ADDR___XMEM_ERR_ADDR: + return true; + default: + return cs47l90_is_adsp_memory(reg); + } +} + +const struct regmap_config cs47l90_16bit_spi_regmap = { + .name = "cs47l90_16bit", + .reg_bits = 32, + .pad_bits = 16, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_INTERRUPT_RAW_STATUS_1, + .readable_reg = cs47l90_16bit_readable_register, + .volatile_reg = cs47l90_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = cs47l90_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs47l90_reg_default), +}; +EXPORT_SYMBOL_GPL(cs47l90_16bit_spi_regmap); + +const struct regmap_config cs47l90_16bit_i2c_regmap = { + .name = "cs47l90_16bit", + .reg_bits = 32, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_INTERRUPT_RAW_STATUS_1, + .readable_reg = cs47l90_16bit_readable_register, + .volatile_reg = cs47l90_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = cs47l90_reg_default, + .num_reg_defaults = ARRAY_SIZE(cs47l90_reg_default), +}; +EXPORT_SYMBOL_GPL(cs47l90_16bit_i2c_regmap); + +const struct regmap_config cs47l90_32bit_spi_regmap = { + .name = "cs47l90_32bit", + .reg_bits = 32, + .reg_stride = 2, + .pad_bits = 16, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_DSP7_PMEM_ERR_ADDR___XMEM_ERR_ADDR, + .readable_reg = cs47l90_32bit_readable_register, + .volatile_reg = cs47l90_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs47l90_32bit_spi_regmap); + +const struct regmap_config cs47l90_32bit_i2c_regmap = { + .name = "cs47l90_32bit", + .reg_bits = 32, + .reg_stride = 2, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + + .max_register = MADERA_DSP7_PMEM_ERR_ADDR___XMEM_ERR_ADDR, + .readable_reg = cs47l90_32bit_readable_register, + .volatile_reg = cs47l90_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(cs47l90_32bit_i2c_regmap); diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c index 6c2870d4e754..6e4ce49b4405 100644 --- a/drivers/mfd/da9063-core.c +++ b/drivers/mfd/da9063-core.c @@ -76,7 +76,7 @@ static struct resource da9063_hwmon_resources[] = { }; -static const struct mfd_cell da9063_devs[] = { +static const struct mfd_cell da9063_common_devs[] = { { .name = DA9063_DRVNAME_REGULATORS, .num_resources = ARRAY_SIZE(da9063_regulators_resources), @@ -101,14 +101,18 @@ static const struct mfd_cell da9063_devs[] = { .of_compatible = "dlg,da9063-onkey", }, { + .name = DA9063_DRVNAME_VIBRATION, + }, +}; + +/* Only present on DA9063 , not on DA9063L */ +static const struct mfd_cell da9063_devs[] = { + { .name = DA9063_DRVNAME_RTC, .num_resources = ARRAY_SIZE(da9063_rtc_resources), .resources = da9063_rtc_resources, .of_compatible = "dlg,da9063-rtc", }, - { - .name = DA9063_DRVNAME_VIBRATION, - }, }; static int da9063_clear_fault_log(struct da9063 *da9063) @@ -192,7 +196,7 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq) dev_err(da9063->dev, "Cannot read chip model id.\n"); return -EIO; } - if (model != PMIC_DA9063) { + if (model != PMIC_CHIP_ID_DA9063) { dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model); return -ENODEV; } @@ -215,7 +219,6 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq) return -ENODEV; } - da9063->model = model; da9063->variant_code = variant_code; ret = da9063_irq_init(da9063); @@ -226,19 +229,26 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq) da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq); - ret = mfd_add_devices(da9063->dev, -1, da9063_devs, - ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base, - NULL); - if (ret) - dev_err(da9063->dev, "Cannot add MFD cells\n"); + ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE, + da9063_common_devs, + ARRAY_SIZE(da9063_common_devs), + NULL, da9063->irq_base, NULL); + if (ret) { + dev_err(da9063->dev, "Failed to add child devices\n"); + return ret; + } - return ret; -} + if (da9063->type == PMIC_TYPE_DA9063) { + ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE, + da9063_devs, ARRAY_SIZE(da9063_devs), + NULL, da9063->irq_base, NULL); + if (ret) { + dev_err(da9063->dev, "Failed to add child devices\n"); + return ret; + } + } -void da9063_device_exit(struct da9063 *da9063) -{ - mfd_remove_devices(da9063->dev); - da9063_irq_exit(da9063); + return ret; } MODULE_DESCRIPTION("PMIC driver for Dialog DA9063"); diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c index 981805a2c521..50a24b1921d0 100644 --- a/drivers/mfd/da9063-i2c.c +++ b/drivers/mfd/da9063-i2c.c @@ -29,78 +29,33 @@ #include <linux/regulator/of_regulator.h> static const struct regmap_range da9063_ad_readable_ranges[] = { - { - .range_min = DA9063_REG_PAGE_CON, - .range_max = DA9063_AD_REG_SECOND_D, - }, { - .range_min = DA9063_REG_SEQ, - .range_max = DA9063_REG_ID_32_31, - }, { - .range_min = DA9063_REG_SEQ_A, - .range_max = DA9063_REG_AUTO3_LOW, - }, { - .range_min = DA9063_REG_T_OFFSET, - .range_max = DA9063_AD_REG_GP_ID_19, - }, { - .range_min = DA9063_REG_CHIP_ID, - .range_max = DA9063_REG_CHIP_VARIANT, - }, + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_AD_REG_SECOND_D), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), + regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), + regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_AD_REG_GP_ID_19), + regmap_reg_range(DA9063_REG_CHIP_ID, DA9063_REG_CHIP_VARIANT), }; static const struct regmap_range da9063_ad_writeable_ranges[] = { - { - .range_min = DA9063_REG_PAGE_CON, - .range_max = DA9063_REG_PAGE_CON, - }, { - .range_min = DA9063_REG_FAULT_LOG, - .range_max = DA9063_REG_VSYS_MON, - }, { - .range_min = DA9063_REG_COUNT_S, - .range_max = DA9063_AD_REG_ALARM_Y, - }, { - .range_min = DA9063_REG_SEQ, - .range_max = DA9063_REG_ID_32_31, - }, { - .range_min = DA9063_REG_SEQ_A, - .range_max = DA9063_REG_AUTO3_LOW, - }, { - .range_min = DA9063_REG_CONFIG_I, - .range_max = DA9063_AD_REG_MON_REG_4, - }, { - .range_min = DA9063_AD_REG_GP_ID_0, - .range_max = DA9063_AD_REG_GP_ID_19, - }, + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON), + regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON), + regmap_reg_range(DA9063_REG_COUNT_S, DA9063_AD_REG_ALARM_Y), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), + regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), + regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_AD_REG_MON_REG_4), + regmap_reg_range(DA9063_AD_REG_GP_ID_0, DA9063_AD_REG_GP_ID_19), }; static const struct regmap_range da9063_ad_volatile_ranges[] = { - { - .range_min = DA9063_REG_PAGE_CON, - .range_max = DA9063_REG_EVENT_D, - }, { - .range_min = DA9063_REG_CONTROL_A, - .range_max = DA9063_REG_CONTROL_B, - }, { - .range_min = DA9063_REG_CONTROL_E, - .range_max = DA9063_REG_CONTROL_F, - }, { - .range_min = DA9063_REG_BCORE2_CONT, - .range_max = DA9063_REG_LDO11_CONT, - }, { - .range_min = DA9063_REG_DVC_1, - .range_max = DA9063_REG_ADC_MAN, - }, { - .range_min = DA9063_REG_ADC_RES_L, - .range_max = DA9063_AD_REG_SECOND_D, - }, { - .range_min = DA9063_REG_SEQ, - .range_max = DA9063_REG_SEQ, - }, { - .range_min = DA9063_REG_EN_32K, - .range_max = DA9063_REG_EN_32K, - }, { - .range_min = DA9063_AD_REG_MON_REG_5, - .range_max = DA9063_AD_REG_MON_REG_6, - }, + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D), + regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B), + regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F), + regmap_reg_range(DA9063_REG_BCORE2_CONT, DA9063_REG_LDO11_CONT), + regmap_reg_range(DA9063_REG_DVC_1, DA9063_REG_ADC_MAN), + regmap_reg_range(DA9063_REG_ADC_RES_L, DA9063_AD_REG_SECOND_D), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_SEQ), + regmap_reg_range(DA9063_REG_EN_32K, DA9063_REG_EN_32K), + regmap_reg_range(DA9063_AD_REG_MON_REG_5, DA9063_AD_REG_MON_REG_6), }; static const struct regmap_access_table da9063_ad_readable_table = { @@ -119,78 +74,33 @@ static const struct regmap_access_table da9063_ad_volatile_table = { }; static const struct regmap_range da9063_bb_readable_ranges[] = { - { - .range_min = DA9063_REG_PAGE_CON, - .range_max = DA9063_BB_REG_SECOND_D, - }, { - .range_min = DA9063_REG_SEQ, - .range_max = DA9063_REG_ID_32_31, - }, { - .range_min = DA9063_REG_SEQ_A, - .range_max = DA9063_REG_AUTO3_LOW, - }, { - .range_min = DA9063_REG_T_OFFSET, - .range_max = DA9063_BB_REG_GP_ID_19, - }, { - .range_min = DA9063_REG_CHIP_ID, - .range_max = DA9063_REG_CHIP_VARIANT, - }, + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_BB_REG_SECOND_D), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), + regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), + regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19), + regmap_reg_range(DA9063_REG_CHIP_ID, DA9063_REG_CHIP_VARIANT), }; static const struct regmap_range da9063_bb_writeable_ranges[] = { - { - .range_min = DA9063_REG_PAGE_CON, - .range_max = DA9063_REG_PAGE_CON, - }, { - .range_min = DA9063_REG_FAULT_LOG, - .range_max = DA9063_REG_VSYS_MON, - }, { - .range_min = DA9063_REG_COUNT_S, - .range_max = DA9063_BB_REG_ALARM_Y, - }, { - .range_min = DA9063_REG_SEQ, - .range_max = DA9063_REG_ID_32_31, - }, { - .range_min = DA9063_REG_SEQ_A, - .range_max = DA9063_REG_AUTO3_LOW, - }, { - .range_min = DA9063_REG_CONFIG_I, - .range_max = DA9063_BB_REG_MON_REG_4, - }, { - .range_min = DA9063_BB_REG_GP_ID_0, - .range_max = DA9063_BB_REG_GP_ID_19, - }, + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON), + regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON), + regmap_reg_range(DA9063_REG_COUNT_S, DA9063_BB_REG_ALARM_Y), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), + regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), + regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4), + regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19), }; static const struct regmap_range da9063_bb_volatile_ranges[] = { - { - .range_min = DA9063_REG_PAGE_CON, - .range_max = DA9063_REG_EVENT_D, - }, { - .range_min = DA9063_REG_CONTROL_A, - .range_max = DA9063_REG_CONTROL_B, - }, { - .range_min = DA9063_REG_CONTROL_E, - .range_max = DA9063_REG_CONTROL_F, - }, { - .range_min = DA9063_REG_BCORE2_CONT, - .range_max = DA9063_REG_LDO11_CONT, - }, { - .range_min = DA9063_REG_DVC_1, - .range_max = DA9063_REG_ADC_MAN, - }, { - .range_min = DA9063_REG_ADC_RES_L, - .range_max = DA9063_BB_REG_SECOND_D, - }, { - .range_min = DA9063_REG_SEQ, - .range_max = DA9063_REG_SEQ, - }, { - .range_min = DA9063_REG_EN_32K, - .range_max = DA9063_REG_EN_32K, - }, { - .range_min = DA9063_BB_REG_MON_REG_5, - .range_max = DA9063_BB_REG_MON_REG_6, - }, + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D), + regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B), + regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F), + regmap_reg_range(DA9063_REG_BCORE2_CONT, DA9063_REG_LDO11_CONT), + regmap_reg_range(DA9063_REG_DVC_1, DA9063_REG_ADC_MAN), + regmap_reg_range(DA9063_REG_ADC_RES_L, DA9063_BB_REG_SECOND_D), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_SEQ), + regmap_reg_range(DA9063_REG_EN_32K, DA9063_REG_EN_32K), + regmap_reg_range(DA9063_BB_REG_MON_REG_5, DA9063_BB_REG_MON_REG_6), }; static const struct regmap_access_table da9063_bb_readable_table = { @@ -208,6 +118,50 @@ static const struct regmap_access_table da9063_bb_volatile_table = { .n_yes_ranges = ARRAY_SIZE(da9063_bb_volatile_ranges), }; +static const struct regmap_range da9063l_bb_readable_ranges[] = { + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_MON_A10_RES), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), + regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), + regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19), + regmap_reg_range(DA9063_REG_CHIP_ID, DA9063_REG_CHIP_VARIANT), +}; + +static const struct regmap_range da9063l_bb_writeable_ranges[] = { + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON), + regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), + regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), + regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4), + regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19), +}; + +static const struct regmap_range da9063l_bb_volatile_ranges[] = { + regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D), + regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B), + regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F), + regmap_reg_range(DA9063_REG_BCORE2_CONT, DA9063_REG_LDO11_CONT), + regmap_reg_range(DA9063_REG_DVC_1, DA9063_REG_ADC_MAN), + regmap_reg_range(DA9063_REG_ADC_RES_L, DA9063_REG_MON_A10_RES), + regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_SEQ), + regmap_reg_range(DA9063_REG_EN_32K, DA9063_REG_EN_32K), + regmap_reg_range(DA9063_BB_REG_MON_REG_5, DA9063_BB_REG_MON_REG_6), +}; + +static const struct regmap_access_table da9063l_bb_readable_table = { + .yes_ranges = da9063l_bb_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063l_bb_readable_ranges), +}; + +static const struct regmap_access_table da9063l_bb_writeable_table = { + .yes_ranges = da9063l_bb_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063l_bb_writeable_ranges), +}; + +static const struct regmap_access_table da9063l_bb_volatile_table = { + .yes_ranges = da9063l_bb_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063l_bb_volatile_ranges), +}; + static const struct regmap_range_cfg da9063_range_cfg[] = { { .range_min = DA9063_REG_PAGE_CON, @@ -232,11 +186,12 @@ static struct regmap_config da9063_regmap_config = { static const struct of_device_id da9063_dt_ids[] = { { .compatible = "dlg,da9063", }, + { .compatible = "dlg,da9063l", }, { } }; MODULE_DEVICE_TABLE(of, da9063_dt_ids); static int da9063_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct da9063 *da9063; int ret; @@ -248,11 +203,16 @@ static int da9063_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, da9063); da9063->dev = &i2c->dev; da9063->chip_irq = i2c->irq; + da9063->type = id->driver_data; if (da9063->variant_code == PMIC_DA9063_AD) { da9063_regmap_config.rd_table = &da9063_ad_readable_table; da9063_regmap_config.wr_table = &da9063_ad_writeable_table; da9063_regmap_config.volatile_table = &da9063_ad_volatile_table; + } else if (da9063->type == PMIC_TYPE_DA9063L) { + da9063_regmap_config.rd_table = &da9063l_bb_readable_table; + da9063_regmap_config.wr_table = &da9063l_bb_writeable_table; + da9063_regmap_config.volatile_table = &da9063l_bb_volatile_table; } else { da9063_regmap_config.rd_table = &da9063_bb_readable_table; da9063_regmap_config.wr_table = &da9063_bb_writeable_table; @@ -270,17 +230,9 @@ static int da9063_i2c_probe(struct i2c_client *i2c, return da9063_device_init(da9063, i2c->irq); } -static int da9063_i2c_remove(struct i2c_client *i2c) -{ - struct da9063 *da9063 = i2c_get_clientdata(i2c); - - da9063_device_exit(da9063); - - return 0; -} - static const struct i2c_device_id da9063_i2c_id[] = { - {"da9063", PMIC_DA9063}, + { "da9063", PMIC_TYPE_DA9063 }, + { "da9063l", PMIC_TYPE_DA9063L }, {}, }; MODULE_DEVICE_TABLE(i2c, da9063_i2c_id); @@ -291,7 +243,6 @@ static struct i2c_driver da9063_i2c_driver = { .of_match_table = of_match_ptr(da9063_dt_ids), }, .probe = da9063_i2c_probe, - .remove = da9063_i2c_remove, .id_table = da9063_i2c_id, }; diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c index 207bbfe55449..ecc0c8ce6c58 100644 --- a/drivers/mfd/da9063-irq.c +++ b/drivers/mfd/da9063-irq.c @@ -28,132 +28,145 @@ static const struct regmap_irq da9063_irqs[] = { /* DA9063 event A register */ - [DA9063_IRQ_ONKEY] = { - .reg_offset = DA9063_REG_EVENT_A_OFFSET, - .mask = DA9063_M_ONKEY, - }, - [DA9063_IRQ_ALARM] = { - .reg_offset = DA9063_REG_EVENT_A_OFFSET, - .mask = DA9063_M_ALARM, - }, - [DA9063_IRQ_TICK] = { - .reg_offset = DA9063_REG_EVENT_A_OFFSET, - .mask = DA9063_M_TICK, - }, - [DA9063_IRQ_ADC_RDY] = { - .reg_offset = DA9063_REG_EVENT_A_OFFSET, - .mask = DA9063_M_ADC_RDY, - }, - [DA9063_IRQ_SEQ_RDY] = { - .reg_offset = DA9063_REG_EVENT_A_OFFSET, - .mask = DA9063_M_SEQ_RDY, - }, + REGMAP_IRQ_REG(DA9063_IRQ_ONKEY, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_ONKEY), + REGMAP_IRQ_REG(DA9063_IRQ_ALARM, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_ALARM), + REGMAP_IRQ_REG(DA9063_IRQ_TICK, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_TICK), + REGMAP_IRQ_REG(DA9063_IRQ_ADC_RDY, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_ADC_RDY), + REGMAP_IRQ_REG(DA9063_IRQ_SEQ_RDY, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_SEQ_RDY), /* DA9063 event B register */ - [DA9063_IRQ_WAKE] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_WAKE, - }, - [DA9063_IRQ_TEMP] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_TEMP, - }, - [DA9063_IRQ_COMP_1V2] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_COMP_1V2, - }, - [DA9063_IRQ_LDO_LIM] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_LDO_LIM, - }, - [DA9063_IRQ_REG_UVOV] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_UVOV, - }, - [DA9063_IRQ_DVC_RDY] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_DVC_RDY, - }, - [DA9063_IRQ_VDD_MON] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_VDD_MON, - }, - [DA9063_IRQ_WARN] = { - .reg_offset = DA9063_REG_EVENT_B_OFFSET, - .mask = DA9063_M_VDD_WARN, - }, + REGMAP_IRQ_REG(DA9063_IRQ_WAKE, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_WAKE), + REGMAP_IRQ_REG(DA9063_IRQ_TEMP, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_TEMP), + REGMAP_IRQ_REG(DA9063_IRQ_COMP_1V2, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_COMP_1V2), + REGMAP_IRQ_REG(DA9063_IRQ_LDO_LIM, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_LDO_LIM), + REGMAP_IRQ_REG(DA9063_IRQ_REG_UVOV, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_UVOV), + REGMAP_IRQ_REG(DA9063_IRQ_DVC_RDY, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_DVC_RDY), + REGMAP_IRQ_REG(DA9063_IRQ_VDD_MON, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_VDD_MON), + REGMAP_IRQ_REG(DA9063_IRQ_WARN, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_VDD_WARN), /* DA9063 event C register */ - [DA9063_IRQ_GPI0] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI0, - }, - [DA9063_IRQ_GPI1] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI1, - }, - [DA9063_IRQ_GPI2] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI2, - }, - [DA9063_IRQ_GPI3] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI3, - }, - [DA9063_IRQ_GPI4] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI4, - }, - [DA9063_IRQ_GPI5] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI5, - }, - [DA9063_IRQ_GPI6] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI6, - }, - [DA9063_IRQ_GPI7] = { - .reg_offset = DA9063_REG_EVENT_C_OFFSET, - .mask = DA9063_M_GPI7, - }, + REGMAP_IRQ_REG(DA9063_IRQ_GPI0, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI0), + REGMAP_IRQ_REG(DA9063_IRQ_GPI1, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI1), + REGMAP_IRQ_REG(DA9063_IRQ_GPI2, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI2), + REGMAP_IRQ_REG(DA9063_IRQ_GPI3, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI3), + REGMAP_IRQ_REG(DA9063_IRQ_GPI4, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI4), + REGMAP_IRQ_REG(DA9063_IRQ_GPI5, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI5), + REGMAP_IRQ_REG(DA9063_IRQ_GPI6, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI6), + REGMAP_IRQ_REG(DA9063_IRQ_GPI7, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI7), /* DA9063 event D register */ - [DA9063_IRQ_GPI8] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI8, - }, - [DA9063_IRQ_GPI9] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI9, - }, - [DA9063_IRQ_GPI10] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI10, - }, - [DA9063_IRQ_GPI11] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI11, - }, - [DA9063_IRQ_GPI12] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI12, - }, - [DA9063_IRQ_GPI13] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI13, - }, - [DA9063_IRQ_GPI14] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI14, - }, - [DA9063_IRQ_GPI15] = { - .reg_offset = DA9063_REG_EVENT_D_OFFSET, - .mask = DA9063_M_GPI15, - }, + REGMAP_IRQ_REG(DA9063_IRQ_GPI8, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI8), + REGMAP_IRQ_REG(DA9063_IRQ_GPI9, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI9), + REGMAP_IRQ_REG(DA9063_IRQ_GPI10, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI10), + REGMAP_IRQ_REG(DA9063_IRQ_GPI11, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI11), + REGMAP_IRQ_REG(DA9063_IRQ_GPI12, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI12), + REGMAP_IRQ_REG(DA9063_IRQ_GPI13, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI13), + REGMAP_IRQ_REG(DA9063_IRQ_GPI14, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI14), + REGMAP_IRQ_REG(DA9063_IRQ_GPI15, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI15), }; static const struct regmap_irq_chip da9063_irq_chip = { .name = "da9063-irq", .irqs = da9063_irqs, - .num_irqs = DA9063_NUM_IRQ, + .num_irqs = ARRAY_SIZE(da9063_irqs), + .num_regs = 4, + .status_base = DA9063_REG_EVENT_A, + .mask_base = DA9063_REG_IRQ_MASK_A, + .ack_base = DA9063_REG_EVENT_A, + .init_ack_masked = true, +}; + +static const struct regmap_irq da9063l_irqs[] = { + /* DA9063 event A register */ + REGMAP_IRQ_REG(DA9063_IRQ_ONKEY, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_ONKEY), + REGMAP_IRQ_REG(DA9063_IRQ_ADC_RDY, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_ADC_RDY), + REGMAP_IRQ_REG(DA9063_IRQ_SEQ_RDY, + DA9063_REG_EVENT_A_OFFSET, DA9063_M_SEQ_RDY), + /* DA9063 event B register */ + REGMAP_IRQ_REG(DA9063_IRQ_WAKE, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_WAKE), + REGMAP_IRQ_REG(DA9063_IRQ_TEMP, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_TEMP), + REGMAP_IRQ_REG(DA9063_IRQ_COMP_1V2, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_COMP_1V2), + REGMAP_IRQ_REG(DA9063_IRQ_LDO_LIM, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_LDO_LIM), + REGMAP_IRQ_REG(DA9063_IRQ_REG_UVOV, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_UVOV), + REGMAP_IRQ_REG(DA9063_IRQ_DVC_RDY, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_DVC_RDY), + REGMAP_IRQ_REG(DA9063_IRQ_VDD_MON, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_VDD_MON), + REGMAP_IRQ_REG(DA9063_IRQ_WARN, + DA9063_REG_EVENT_B_OFFSET, DA9063_M_VDD_WARN), + /* DA9063 event C register */ + REGMAP_IRQ_REG(DA9063_IRQ_GPI0, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI0), + REGMAP_IRQ_REG(DA9063_IRQ_GPI1, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI1), + REGMAP_IRQ_REG(DA9063_IRQ_GPI2, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI2), + REGMAP_IRQ_REG(DA9063_IRQ_GPI3, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI3), + REGMAP_IRQ_REG(DA9063_IRQ_GPI4, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI4), + REGMAP_IRQ_REG(DA9063_IRQ_GPI5, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI5), + REGMAP_IRQ_REG(DA9063_IRQ_GPI6, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI6), + REGMAP_IRQ_REG(DA9063_IRQ_GPI7, + DA9063_REG_EVENT_C_OFFSET, DA9063_M_GPI7), + /* DA9063 event D register */ + REGMAP_IRQ_REG(DA9063_IRQ_GPI8, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI8), + REGMAP_IRQ_REG(DA9063_IRQ_GPI9, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI9), + REGMAP_IRQ_REG(DA9063_IRQ_GPI10, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI10), + REGMAP_IRQ_REG(DA9063_IRQ_GPI11, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI11), + REGMAP_IRQ_REG(DA9063_IRQ_GPI12, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI12), + REGMAP_IRQ_REG(DA9063_IRQ_GPI13, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI13), + REGMAP_IRQ_REG(DA9063_IRQ_GPI14, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI14), + REGMAP_IRQ_REG(DA9063_IRQ_GPI15, + DA9063_REG_EVENT_D_OFFSET, DA9063_M_GPI15), +}; +static const struct regmap_irq_chip da9063l_irq_chip = { + .name = "da9063l-irq", + .irqs = da9063l_irqs, + .num_irqs = ARRAY_SIZE(da9063l_irqs), .num_regs = 4, .status_base = DA9063_REG_EVENT_A, .mask_base = DA9063_REG_IRQ_MASK_A, @@ -163,6 +176,7 @@ static const struct regmap_irq_chip da9063_irq_chip = { int da9063_irq_init(struct da9063 *da9063) { + const struct regmap_irq_chip *irq_chip; int ret; if (!da9063->chip_irq) { @@ -170,10 +184,15 @@ int da9063_irq_init(struct da9063 *da9063) return -EINVAL; } - ret = regmap_add_irq_chip(da9063->regmap, da9063->chip_irq, + if (da9063->type == PMIC_TYPE_DA9063) + irq_chip = &da9063_irq_chip; + else + irq_chip = &da9063l_irq_chip; + + ret = devm_regmap_add_irq_chip(da9063->dev, da9063->regmap, + da9063->chip_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, - da9063->irq_base, &da9063_irq_chip, - &da9063->regmap_irq); + da9063->irq_base, irq_chip, &da9063->regmap_irq); if (ret) { dev_err(da9063->dev, "Failed to reguest IRQ %d: %d\n", da9063->chip_irq, ret); @@ -182,8 +201,3 @@ int da9063_irq_init(struct da9063 *da9063) return 0; } - -void da9063_irq_exit(struct da9063 *da9063) -{ - regmap_del_irq_chip(da9063->chip_irq, da9063->regmap_irq); -} diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c index 704e189ca162..90e789943466 100644 --- a/drivers/mfd/dln2.c +++ b/drivers/mfd/dln2.c @@ -194,6 +194,7 @@ static bool dln2_transfer_complete(struct dln2_dev *dln2, struct urb *urb, struct device *dev = &dln2->interface->dev; struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle]; struct dln2_rx_context *rxc; + unsigned long flags; bool valid_slot = false; if (rx_slot >= DLN2_MAX_RX_SLOTS) @@ -201,18 +202,13 @@ static bool dln2_transfer_complete(struct dln2_dev *dln2, struct urb *urb, rxc = &rxs->slots[rx_slot]; - /* - * No need to disable interrupts as this lock is not taken in interrupt - * context elsewhere in this driver. This function (or its callers) are - * also not exported to other modules. - */ - spin_lock(&rxs->lock); + spin_lock_irqsave(&rxs->lock, flags); if (rxc->in_use && !rxc->urb) { rxc->urb = urb; complete(&rxc->done); valid_slot = true; } - spin_unlock(&rxs->lock); + spin_unlock_irqrestore(&rxs->lock, flags); out: if (!valid_slot) diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index c37ccbfd52f2..96c07fa1802a 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -49,7 +49,7 @@ static struct regmap_config hi655x_regmap_config = { .reg_bits = 32, .reg_stride = HI655X_STRIDE, .val_bits = 8, - .max_register = HI655X_BUS_ADDR(0xFFF), + .max_register = HI655X_BUS_ADDR(0x400) - HI655X_STRIDE, }; static struct resource pwrkey_resources[] = { diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index d9ae983095c5..0e5282fc1467 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -178,6 +178,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_info }, + /* ICL-LP */ + { PCI_VDEVICE(INTEL, 0x34a8), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x34a9), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x34c5), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x34c6), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x34c7), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x34e8), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x34e9), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info }, /* APL */ { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info }, { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info }, diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 390b27cb2c2e..fb5a10b8317d 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -143,7 +143,7 @@ static struct platform_device *kempld_pdev; static int kempld_create_platform_device(const struct dmi_system_id *id) { - struct kempld_platform_data *pdata = id->driver_data; + const struct kempld_platform_data *pdata = id->driver_data; int ret; kempld_pdev = platform_device_alloc("kempld", -1); @@ -259,7 +259,7 @@ EXPORT_SYMBOL_GPL(kempld_write32); */ void kempld_get_mutex(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); mutex_lock(&pld->lock); pdata->get_hardware_mutex(pld); @@ -272,7 +272,7 @@ EXPORT_SYMBOL_GPL(kempld_get_mutex); */ void kempld_release_mutex(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); pdata->release_hardware_mutex(pld); mutex_unlock(&pld->lock); @@ -290,7 +290,7 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex); static int kempld_get_info(struct kempld_device_data *pld) { int ret; - struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); char major, minor; ret = pdata->get_info(pld); @@ -332,7 +332,7 @@ static int kempld_get_info(struct kempld_device_data *pld) */ static int kempld_register_cells(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); return pdata->register_cells(pld); } @@ -444,7 +444,8 @@ static int kempld_detect_device(struct kempld_device_data *pld) static int kempld_probe(struct platform_device *pdev) { - struct kempld_platform_data *pdata = dev_get_platdata(&pdev->dev); + const struct kempld_platform_data *pdata = + dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct kempld_device_data *pld; struct resource *ioport; @@ -476,7 +477,7 @@ static int kempld_probe(struct platform_device *pdev) static int kempld_remove(struct platform_device *pdev) { struct kempld_device_data *pld = platform_get_drvdata(pdev); - struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c new file mode 100644 index 000000000000..8cfea969b060 --- /dev/null +++ b/drivers/mfd/madera-core.c @@ -0,0 +1,609 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Core MFD support for Cirrus Logic Madera codecs + * + * Copyright (C) 2015-2018 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> + +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/registers.h> + +#include "madera.h" + +#define CS47L35_SILICON_ID 0x6360 +#define CS47L85_SILICON_ID 0x6338 +#define CS47L90_SILICON_ID 0x6364 + +#define MADERA_32KZ_MCLK2 1 + +static const char * const madera_core_supplies[] = { + "AVDD", + "DBVDD1", +}; + +static const struct mfd_cell madera_ldo1_devs[] = { + { .name = "madera-ldo1" }, +}; + +static const char * const cs47l35_supplies[] = { + "MICVDD", + "DBVDD2", + "CPVDD1", + "CPVDD2", + "SPKVDD", +}; + +static const struct mfd_cell cs47l35_devs[] = { + { .name = "madera-pinctrl", }, + { .name = "madera-irq", }, + { .name = "madera-micsupp", }, + { .name = "madera-gpio", }, + { .name = "madera-extcon", }, + { + .name = "cs47l35-codec", + .parent_supplies = cs47l35_supplies, + .num_parent_supplies = ARRAY_SIZE(cs47l35_supplies), + }, +}; + +static const char * const cs47l85_supplies[] = { + "MICVDD", + "DBVDD2", + "DBVDD3", + "DBVDD4", + "CPVDD1", + "CPVDD2", + "SPKVDDL", + "SPKVDDR", +}; + +static const struct mfd_cell cs47l85_devs[] = { + { .name = "madera-pinctrl", }, + { .name = "madera-irq", }, + { .name = "madera-micsupp" }, + { .name = "madera-gpio", }, + { .name = "madera-extcon", }, + { + .name = "cs47l85-codec", + .parent_supplies = cs47l85_supplies, + .num_parent_supplies = ARRAY_SIZE(cs47l85_supplies), + }, +}; + +static const char * const cs47l90_supplies[] = { + "MICVDD", + "DBVDD2", + "DBVDD3", + "DBVDD4", + "CPVDD1", + "CPVDD2", +}; + +static const struct mfd_cell cs47l90_devs[] = { + { .name = "madera-pinctrl", }, + { .name = "madera-irq", }, + { .name = "madera-micsupp", }, + { .name = "madera-gpio", }, + { .name = "madera-extcon", }, + { + .name = "cs47l90-codec", + .parent_supplies = cs47l90_supplies, + .num_parent_supplies = ARRAY_SIZE(cs47l90_supplies), + }, +}; + +/* Used by madera-i2c and madera-spi drivers */ +const char *madera_name_from_type(enum madera_type type) +{ + switch (type) { + case CS47L35: + return "CS47L35"; + case CS47L85: + return "CS47L85"; + case CS47L90: + return "CS47L90"; + case CS47L91: + return "CS47L91"; + case WM1840: + return "WM1840"; + default: + return "Unknown"; + } +} +EXPORT_SYMBOL_GPL(madera_name_from_type); + +#define MADERA_BOOT_POLL_MAX_INTERVAL_US 5000 +#define MADERA_BOOT_POLL_TIMEOUT_US 25000 + +static int madera_wait_for_boot(struct madera *madera) +{ + unsigned int val; + int ret; + + /* + * We can't use an interrupt as we need to runtime resume to do so, + * so we poll the status bit. This won't race with the interrupt + * handler because it will be blocked on runtime resume. + */ + ret = regmap_read_poll_timeout(madera->regmap, + MADERA_IRQ1_RAW_STATUS_1, + val, + (val & MADERA_BOOT_DONE_STS1), + MADERA_BOOT_POLL_MAX_INTERVAL_US, + MADERA_BOOT_POLL_TIMEOUT_US); + + if (ret) + dev_err(madera->dev, "Polling BOOT_DONE_STS failed: %d\n", ret); + + /* + * BOOT_DONE defaults to unmasked on boot so we must ack it. + * Do this unconditionally to avoid interrupt storms. + */ + regmap_write(madera->regmap, MADERA_IRQ1_STATUS_1, + MADERA_BOOT_DONE_EINT1); + + pm_runtime_mark_last_busy(madera->dev); + + return ret; +} + +static int madera_soft_reset(struct madera *madera) +{ + int ret; + + ret = regmap_write(madera->regmap, MADERA_SOFTWARE_RESET, 0); + if (ret != 0) { + dev_err(madera->dev, "Failed to soft reset device: %d\n", ret); + return ret; + } + + /* Allow time for internal clocks to startup after reset */ + usleep_range(1000, 2000); + + return 0; +} + +static void madera_enable_hard_reset(struct madera *madera) +{ + if (!madera->pdata.reset) + return; + + /* + * There are many existing out-of-tree users of these codecs that we + * can't break so preserve the expected behaviour of setting the line + * low to assert reset. + */ + gpiod_set_raw_value_cansleep(madera->pdata.reset, 0); +} + +static void madera_disable_hard_reset(struct madera *madera) +{ + if (!madera->pdata.reset) + return; + + gpiod_set_raw_value_cansleep(madera->pdata.reset, 1); + usleep_range(1000, 2000); +} + +static int __maybe_unused madera_runtime_resume(struct device *dev) +{ + struct madera *madera = dev_get_drvdata(dev); + int ret; + + dev_dbg(dev, "Leaving sleep mode\n"); + + ret = regulator_enable(madera->dcvdd); + if (ret) { + dev_err(dev, "Failed to enable DCVDD: %d\n", ret); + return ret; + } + + regcache_cache_only(madera->regmap, false); + regcache_cache_only(madera->regmap_32bit, false); + + ret = madera_wait_for_boot(madera); + if (ret) + goto err; + + ret = regcache_sync(madera->regmap); + if (ret) { + dev_err(dev, "Failed to restore 16-bit register cache\n"); + goto err; + } + + ret = regcache_sync(madera->regmap_32bit); + if (ret) { + dev_err(dev, "Failed to restore 32-bit register cache\n"); + goto err; + } + + return 0; + +err: + regcache_cache_only(madera->regmap_32bit, true); + regcache_cache_only(madera->regmap, true); + regulator_disable(madera->dcvdd); + + return ret; +} + +static int __maybe_unused madera_runtime_suspend(struct device *dev) +{ + struct madera *madera = dev_get_drvdata(dev); + + dev_dbg(madera->dev, "Entering sleep mode\n"); + + regcache_cache_only(madera->regmap, true); + regcache_mark_dirty(madera->regmap); + regcache_cache_only(madera->regmap_32bit, true); + regcache_mark_dirty(madera->regmap_32bit); + + regulator_disable(madera->dcvdd); + + return 0; +} + +const struct dev_pm_ops madera_pm_ops = { + SET_RUNTIME_PM_OPS(madera_runtime_suspend, + madera_runtime_resume, + NULL) +}; +EXPORT_SYMBOL_GPL(madera_pm_ops); + +const struct of_device_id madera_of_match[] = { + { .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 }, + { .compatible = "cirrus,cs47l85", .data = (void *)CS47L85 }, + { .compatible = "cirrus,cs47l90", .data = (void *)CS47L90 }, + { .compatible = "cirrus,cs47l91", .data = (void *)CS47L91 }, + { .compatible = "cirrus,wm1840", .data = (void *)WM1840 }, + {} +}; +EXPORT_SYMBOL_GPL(madera_of_match); + +static int madera_get_reset_gpio(struct madera *madera) +{ + struct gpio_desc *reset; + int ret; + + if (madera->pdata.reset) + return 0; + + reset = devm_gpiod_get_optional(madera->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset)) { + ret = PTR_ERR(reset); + if (ret != -EPROBE_DEFER) + dev_err(madera->dev, "Failed to request /RESET: %d\n", + ret); + return ret; + } + + /* + * A hard reset is needed for full reset of the chip. We allow running + * without hard reset only because it can be useful for early + * prototyping and some debugging, but we need to warn it's not ideal. + */ + if (!reset) + dev_warn(madera->dev, + "Running without reset GPIO is not recommended\n"); + + madera->pdata.reset = reset; + + return 0; +} + +static void madera_set_micbias_info(struct madera *madera) +{ + /* + * num_childbias is an array because future codecs can have different + * childbiases for each micbias. Unspecified values default to 0. + */ + switch (madera->type) { + case CS47L35: + madera->num_micbias = 2; + madera->num_childbias[0] = 2; + madera->num_childbias[1] = 2; + return; + case CS47L85: + case WM1840: + madera->num_micbias = 4; + /* no child biases */ + return; + case CS47L90: + case CS47L91: + madera->num_micbias = 2; + madera->num_childbias[0] = 4; + madera->num_childbias[1] = 4; + return; + default: + return; + } +} + +int madera_dev_init(struct madera *madera) +{ + struct device *dev = madera->dev; + unsigned int hwid; + int (*patch_fn)(struct madera *) = NULL; + const struct mfd_cell *mfd_devs; + int n_devs = 0; + int i, ret; + + dev_set_drvdata(madera->dev, madera); + BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier); + madera_set_micbias_info(madera); + + /* + * We need writable hw config info that all children can share. + * Simplest to take one shared copy of pdata struct. + */ + if (dev_get_platdata(madera->dev)) { + memcpy(&madera->pdata, dev_get_platdata(madera->dev), + sizeof(madera->pdata)); + } + + ret = madera_get_reset_gpio(madera); + if (ret) + return ret; + + regcache_cache_only(madera->regmap, true); + regcache_cache_only(madera->regmap_32bit, true); + + for (i = 0; i < ARRAY_SIZE(madera_core_supplies); i++) + madera->core_supplies[i].supply = madera_core_supplies[i]; + + madera->num_core_supplies = ARRAY_SIZE(madera_core_supplies); + + /* + * On some codecs DCVDD could be supplied by the internal LDO1. + * For those we must add the LDO1 driver before requesting DCVDD + * No devm_ because we need to control shutdown order of children. + */ + switch (madera->type) { + case CS47L35: + case CS47L90: + case CS47L91: + break; + case CS47L85: + case WM1840: + ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE, + madera_ldo1_devs, + ARRAY_SIZE(madera_ldo1_devs), + NULL, 0, NULL); + if (ret) { + dev_err(dev, "Failed to add LDO1 child: %d\n", ret); + return ret; + } + break; + default: + /* No point continuing if the type is unknown */ + dev_err(madera->dev, "Unknown device type %d\n", madera->type); + return -ENODEV; + } + + ret = devm_regulator_bulk_get(dev, madera->num_core_supplies, + madera->core_supplies); + if (ret) { + dev_err(dev, "Failed to request core supplies: %d\n", ret); + goto err_devs; + } + + /* + * Don't use devres here. If the regulator is one of our children it + * will already have been removed before devres cleanup on this mfd + * driver tries to call put() on it. We need control of shutdown order. + */ + madera->dcvdd = regulator_get(madera->dev, "DCVDD"); + if (IS_ERR(madera->dcvdd)) { + ret = PTR_ERR(madera->dcvdd); + dev_err(dev, "Failed to request DCVDD: %d\n", ret); + goto err_devs; + } + + ret = regulator_bulk_enable(madera->num_core_supplies, + madera->core_supplies); + if (ret) { + dev_err(dev, "Failed to enable core supplies: %d\n", ret); + goto err_dcvdd; + } + + ret = regulator_enable(madera->dcvdd); + if (ret) { + dev_err(dev, "Failed to enable DCVDD: %d\n", ret); + goto err_enable; + } + + madera_disable_hard_reset(madera); + + regcache_cache_only(madera->regmap, false); + regcache_cache_only(madera->regmap_32bit, false); + + /* + * Now we can power up and verify that this is a chip we know about + * before we start doing any writes to its registers. + */ + ret = regmap_read(madera->regmap, MADERA_SOFTWARE_RESET, &hwid); + if (ret) { + dev_err(dev, "Failed to read ID register: %d\n", ret); + goto err_reset; + } + + switch (hwid) { + case CS47L35_SILICON_ID: + if (IS_ENABLED(CONFIG_MFD_CS47L35)) { + switch (madera->type) { + case CS47L35: + patch_fn = cs47l35_patch; + mfd_devs = cs47l35_devs; + n_devs = ARRAY_SIZE(cs47l35_devs); + break; + default: + break; + } + } + break; + case CS47L85_SILICON_ID: + if (IS_ENABLED(CONFIG_MFD_CS47L85)) { + switch (madera->type) { + case CS47L85: + case WM1840: + patch_fn = cs47l85_patch; + mfd_devs = cs47l85_devs; + n_devs = ARRAY_SIZE(cs47l85_devs); + break; + default: + break; + } + } + break; + case CS47L90_SILICON_ID: + if (IS_ENABLED(CONFIG_MFD_CS47L90)) { + switch (madera->type) { + case CS47L90: + case CS47L91: + patch_fn = cs47l90_patch; + mfd_devs = cs47l90_devs; + n_devs = ARRAY_SIZE(cs47l90_devs); + break; + default: + break; + } + } + break; + default: + dev_err(madera->dev, "Unknown device ID: %x\n", hwid); + ret = -EINVAL; + goto err_reset; + } + + if (!n_devs) { + dev_err(madera->dev, "Device ID 0x%x not a %s\n", hwid, + madera->type_name); + ret = -ENODEV; + goto err_reset; + } + + /* + * It looks like a device we support. If we don't have a hard reset + * we can now attempt a soft reset. + */ + if (!madera->pdata.reset) { + ret = madera_soft_reset(madera); + if (ret) + goto err_reset; + } + + ret = madera_wait_for_boot(madera); + if (ret) { + dev_err(madera->dev, "Device failed initial boot: %d\n", ret); + goto err_reset; + } + + ret = regmap_read(madera->regmap, MADERA_HARDWARE_REVISION, + &madera->rev); + if (ret) { + dev_err(dev, "Failed to read revision register: %d\n", ret); + goto err_reset; + } + madera->rev &= MADERA_HW_REVISION_MASK; + + dev_info(dev, "%s silicon revision %d\n", madera->type_name, + madera->rev); + + /* Apply hardware patch */ + if (patch_fn) { + ret = patch_fn(madera); + if (ret) { + dev_err(madera->dev, "Failed to apply patch %d\n", ret); + goto err_reset; + } + } + + /* Init 32k clock sourced from MCLK2 */ + ret = regmap_update_bits(madera->regmap, + MADERA_CLOCK_32K_1, + MADERA_CLK_32K_ENA_MASK | MADERA_CLK_32K_SRC_MASK, + MADERA_CLK_32K_ENA | MADERA_32KZ_MCLK2); + if (ret) { + dev_err(madera->dev, "Failed to init 32k clock: %d\n", ret); + goto err_reset; + } + + pm_runtime_set_active(madera->dev); + pm_runtime_enable(madera->dev); + pm_runtime_set_autosuspend_delay(madera->dev, 100); + pm_runtime_use_autosuspend(madera->dev); + + /* No devm_ because we need to control shutdown order of children */ + ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE, + mfd_devs, n_devs, + NULL, 0, NULL); + if (ret) { + dev_err(madera->dev, "Failed to add subdevices: %d\n", ret); + goto err_pm_runtime; + } + + return 0; + +err_pm_runtime: + pm_runtime_disable(madera->dev); +err_reset: + madera_enable_hard_reset(madera); + regulator_disable(madera->dcvdd); +err_enable: + regulator_bulk_disable(madera->num_core_supplies, + madera->core_supplies); +err_dcvdd: + regulator_put(madera->dcvdd); +err_devs: + mfd_remove_devices(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(madera_dev_init); + +int madera_dev_exit(struct madera *madera) +{ + /* Prevent any IRQs being serviced while we clean up */ + disable_irq(madera->irq); + + /* + * DCVDD could be supplied by a child node, we must disable it before + * removing the children, and prevent PM runtime from turning it back on + */ + pm_runtime_disable(madera->dev); + + regulator_disable(madera->dcvdd); + regulator_put(madera->dcvdd); + + mfd_remove_devices(madera->dev); + madera_enable_hard_reset(madera); + + regulator_bulk_disable(madera->num_core_supplies, + madera->core_supplies); + return 0; +} +EXPORT_SYMBOL_GPL(madera_dev_exit); + +MODULE_DESCRIPTION("Madera core MFD driver"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/madera-i2c.c b/drivers/mfd/madera-i2c.c new file mode 100644 index 000000000000..05ae94be01d8 --- /dev/null +++ b/drivers/mfd/madera-i2c.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * I2C bus interface to Cirrus Logic Madera codecs + * + * Copyright (C) 2015-2018 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +#include <linux/mfd/madera/core.h> + +#include "madera.h" + +static int madera_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct madera *madera; + const struct regmap_config *regmap_16bit_config = NULL; + const struct regmap_config *regmap_32bit_config = NULL; + const void *of_data; + unsigned long type; + const char *name; + int ret; + + of_data = of_device_get_match_data(&i2c->dev); + if (of_data) + type = (unsigned long)of_data; + else + type = id->driver_data; + + switch (type) { + case CS47L35: + if (IS_ENABLED(CONFIG_MFD_CS47L35)) { + regmap_16bit_config = &cs47l35_16bit_i2c_regmap; + regmap_32bit_config = &cs47l35_32bit_i2c_regmap; + } + break; + case CS47L85: + case WM1840: + if (IS_ENABLED(CONFIG_MFD_CS47L85)) { + regmap_16bit_config = &cs47l85_16bit_i2c_regmap; + regmap_32bit_config = &cs47l85_32bit_i2c_regmap; + } + break; + case CS47L90: + case CS47L91: + if (IS_ENABLED(CONFIG_MFD_CS47L90)) { + regmap_16bit_config = &cs47l90_16bit_i2c_regmap; + regmap_32bit_config = &cs47l90_32bit_i2c_regmap; + } + break; + default: + dev_err(&i2c->dev, + "Unknown Madera I2C device type %ld\n", type); + return -EINVAL; + } + + name = madera_name_from_type(type); + + if (!regmap_16bit_config) { + /* it's polite to say which codec isn't built into the kernel */ + dev_err(&i2c->dev, + "Kernel does not include support for %s\n", name); + return -EINVAL; + } + + madera = devm_kzalloc(&i2c->dev, sizeof(*madera), GFP_KERNEL); + if (!madera) + return -ENOMEM; + + + madera->regmap = devm_regmap_init_i2c(i2c, regmap_16bit_config); + if (IS_ERR(madera->regmap)) { + ret = PTR_ERR(madera->regmap); + dev_err(&i2c->dev, + "Failed to allocate 16-bit register map: %d\n", ret); + return ret; + } + + madera->regmap_32bit = devm_regmap_init_i2c(i2c, regmap_32bit_config); + if (IS_ERR(madera->regmap_32bit)) { + ret = PTR_ERR(madera->regmap_32bit); + dev_err(&i2c->dev, + "Failed to allocate 32-bit register map: %d\n", ret); + return ret; + } + + madera->type = type; + madera->type_name = name; + madera->dev = &i2c->dev; + madera->irq = i2c->irq; + + return madera_dev_init(madera); +} + +static int madera_i2c_remove(struct i2c_client *i2c) +{ + struct madera *madera = dev_get_drvdata(&i2c->dev); + + madera_dev_exit(madera); + + return 0; +} + +static const struct i2c_device_id madera_i2c_id[] = { + { "cs47l35", CS47L35 }, + { "cs47l85", CS47L85 }, + { "cs47l90", CS47L90 }, + { "cs47l91", CS47L91 }, + { "wm1840", WM1840 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, madera_i2c_id); + +static struct i2c_driver madera_i2c_driver = { + .driver = { + .name = "madera", + .pm = &madera_pm_ops, + .of_match_table = of_match_ptr(madera_of_match), + }, + .probe = madera_i2c_probe, + .remove = madera_i2c_remove, + .id_table = madera_i2c_id, +}; + +module_i2c_driver(madera_i2c_driver); + +MODULE_DESCRIPTION("Madera I2C bus interface"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c new file mode 100644 index 000000000000..4c398b278bba --- /dev/null +++ b/drivers/mfd/madera-spi.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SPI bus interface to Cirrus Logic Madera codecs + * + * Copyright (C) 2015-2018 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include <linux/mfd/madera/core.h> + +#include "madera.h" + +static int madera_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct madera *madera; + const struct regmap_config *regmap_16bit_config = NULL; + const struct regmap_config *regmap_32bit_config = NULL; + const void *of_data; + unsigned long type; + const char *name; + int ret; + + of_data = of_device_get_match_data(&spi->dev); + if (of_data) + type = (unsigned long)of_data; + else + type = id->driver_data; + + switch (type) { + case CS47L35: + if (IS_ENABLED(CONFIG_MFD_CS47L35)) { + regmap_16bit_config = &cs47l35_16bit_spi_regmap; + regmap_32bit_config = &cs47l35_32bit_spi_regmap; + } + break; + case CS47L85: + case WM1840: + if (IS_ENABLED(CONFIG_MFD_CS47L85)) { + regmap_16bit_config = &cs47l85_16bit_spi_regmap; + regmap_32bit_config = &cs47l85_32bit_spi_regmap; + } + break; + case CS47L90: + case CS47L91: + if (IS_ENABLED(CONFIG_MFD_CS47L90)) { + regmap_16bit_config = &cs47l90_16bit_spi_regmap; + regmap_32bit_config = &cs47l90_32bit_spi_regmap; + } + break; + default: + dev_err(&spi->dev, + "Unknown Madera SPI device type %ld\n", type); + return -EINVAL; + } + + name = madera_name_from_type(type); + + if (!regmap_16bit_config) { + /* it's polite to say which codec isn't built into the kernel */ + dev_err(&spi->dev, + "Kernel does not include support for %s\n", name); + return -EINVAL; + } + + madera = devm_kzalloc(&spi->dev, sizeof(*madera), GFP_KERNEL); + if (!madera) + return -ENOMEM; + + madera->regmap = devm_regmap_init_spi(spi, regmap_16bit_config); + if (IS_ERR(madera->regmap)) { + ret = PTR_ERR(madera->regmap); + dev_err(&spi->dev, + "Failed to allocate 16-bit register map: %d\n", ret); + return ret; + } + + madera->regmap_32bit = devm_regmap_init_spi(spi, regmap_32bit_config); + if (IS_ERR(madera->regmap_32bit)) { + ret = PTR_ERR(madera->regmap_32bit); + dev_err(&spi->dev, + "Failed to allocate 32-bit register map: %d\n", ret); + return ret; + } + + madera->type = type; + madera->type_name = name; + madera->dev = &spi->dev; + madera->irq = spi->irq; + + return madera_dev_init(madera); +} + +static int madera_spi_remove(struct spi_device *spi) +{ + struct madera *madera = spi_get_drvdata(spi); + + madera_dev_exit(madera); + + return 0; +} + +static const struct spi_device_id madera_spi_ids[] = { + { "cs47l35", CS47L35 }, + { "cs47l85", CS47L85 }, + { "cs47l90", CS47L90 }, + { "cs47l91", CS47L91 }, + { "wm1840", WM1840 }, + { } +}; +MODULE_DEVICE_TABLE(spi, madera_spi_ids); + +static struct spi_driver madera_spi_driver = { + .driver = { + .name = "madera", + .pm = &madera_pm_ops, + .of_match_table = of_match_ptr(madera_of_match), + }, + .probe = madera_spi_probe, + .remove = madera_spi_remove, + .id_table = madera_spi_ids, +}; + +module_spi_driver(madera_spi_driver); + +MODULE_DESCRIPTION("Madera SPI bus interface"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/madera.h b/drivers/mfd/madera.h new file mode 100644 index 000000000000..891b84efb9a7 --- /dev/null +++ b/drivers/mfd/madera.h @@ -0,0 +1,44 @@ +/* + * MFD internals for Cirrus Logic Madera codecs + * + * Copyright 2015-2018 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef MADERA_MFD_H +#define MADERA_MFD_H + +#include <linux/of.h> +#include <linux/pm.h> + +struct madera; + +extern const struct dev_pm_ops madera_pm_ops; +extern const struct of_device_id madera_of_match[]; + +int madera_dev_init(struct madera *madera); +int madera_dev_exit(struct madera *madera); + +const char *madera_name_from_type(enum madera_type type); + +extern const struct regmap_config cs47l35_16bit_spi_regmap; +extern const struct regmap_config cs47l35_32bit_spi_regmap; +extern const struct regmap_config cs47l35_16bit_i2c_regmap; +extern const struct regmap_config cs47l35_32bit_i2c_regmap; +int cs47l35_patch(struct madera *madera); + +extern const struct regmap_config cs47l85_16bit_spi_regmap; +extern const struct regmap_config cs47l85_32bit_spi_regmap; +extern const struct regmap_config cs47l85_16bit_i2c_regmap; +extern const struct regmap_config cs47l85_32bit_i2c_regmap; +int cs47l85_patch(struct madera *madera); + +extern const struct regmap_config cs47l90_16bit_spi_regmap; +extern const struct regmap_config cs47l90_32bit_spi_regmap; +extern const struct regmap_config cs47l90_16bit_i2c_regmap; +extern const struct regmap_config cs47l90_32bit_i2c_regmap; +int cs47l90_patch(struct madera *madera); +#endif diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index 36dcd98977d6..2a8369657e38 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -63,16 +63,6 @@ #define RAVE_SP_TX_BUFFER_SIZE \ (RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE) -#define RAVE_SP_BOOT_SOURCE_GET 0 -#define RAVE_SP_BOOT_SOURCE_SET 1 - -#define RAVE_SP_RDU2_BOARD_TYPE_RMB 0 -#define RAVE_SP_RDU2_BOARD_TYPE_DEB 1 - -#define RAVE_SP_BOOT_SOURCE_SD 0 -#define RAVE_SP_BOOT_SOURCE_EMMC 1 -#define RAVE_SP_BOOT_SOURCE_NOR 2 - /** * enum rave_sp_deframer_state - Possible state for de-framer * @@ -127,14 +117,44 @@ struct rave_sp_checksum { void (*subroutine)(const u8 *, size_t, u8 *); }; +struct rave_sp_version { + u8 hardware; + __le16 major; + u8 minor; + u8 letter[2]; +} __packed; + +struct rave_sp_status { + struct rave_sp_version bootloader_version; + struct rave_sp_version firmware_version; + u16 rdu_eeprom_flag; + u16 dds_eeprom_flag; + u8 pic_flag; + u8 orientation; + u32 etc; + s16 temp[2]; + u8 backlight_current[3]; + u8 dip_switch; + u8 host_interrupt; + u16 voltage_28; + u8 i2c_device_status; + u8 power_status; + u8 general_status; + u8 deprecated1; + u8 power_led_status; + u8 deprecated2; + u8 periph_power_shutoff; +} __packed; + /** * struct rave_sp_variant_cmds - Variant specific command routines * * @translate: Generic to variant specific command mapping routine - * + * @get_status: Variant specific implementation of CMD_GET_STATUS */ struct rave_sp_variant_cmds { int (*translate)(enum rave_sp_command); + int (*get_status)(struct rave_sp *sp, struct rave_sp_status *); }; /** @@ -180,35 +200,6 @@ struct rave_sp { const char *part_number_bootloader; }; -struct rave_sp_version { - u8 hardware; - __le16 major; - u8 minor; - u8 letter[2]; -} __packed; - -struct rave_sp_status { - struct rave_sp_version bootloader_version; - struct rave_sp_version firmware_version; - u16 rdu_eeprom_flag; - u16 dds_eeprom_flag; - u8 pic_flag; - u8 orientation; - u32 etc; - s16 temp[2]; - u8 backlight_current[3]; - u8 dip_switch; - u8 host_interrupt; - u16 voltage_28; - u8 i2c_device_status; - u8 power_status; - u8 general_status; - u8 deprecated1; - u8 power_led_status; - u8 deprecated2; - u8 periph_power_shutoff; -} __packed; - static bool rave_sp_id_is_event(u8 code) { return (code & 0xF0) == RAVE_SP_EVNT_BASE; @@ -641,10 +632,14 @@ static int rave_sp_default_cmd_translate(enum rave_sp_command command) return 0x14; case RAVE_SP_CMD_SW_WDT: return 0x1C; + case RAVE_SP_CMD_PET_WDT: + return 0x1D; case RAVE_SP_CMD_RESET: return 0x1E; case RAVE_SP_CMD_RESET_REASON: return 0x1F; + case RAVE_SP_CMD_RMB_EEPROM: + return 0x20; default: return -EINVAL; } @@ -666,18 +661,44 @@ static const char *devm_rave_sp_version(struct device *dev, version->letter[1]); } -static int rave_sp_get_status(struct rave_sp *sp) +static int rave_sp_rdu1_get_status(struct rave_sp *sp, + struct rave_sp_status *status) { - struct device *dev = &sp->serdev->dev; u8 cmd[] = { [0] = RAVE_SP_CMD_STATUS, [1] = 0 }; + + return rave_sp_exec(sp, cmd, sizeof(cmd), status, sizeof(*status)); +} + +static int rave_sp_emulated_get_status(struct rave_sp *sp, + struct rave_sp_status *status) +{ + u8 cmd[] = { + [0] = RAVE_SP_CMD_GET_FIRMWARE_VERSION, + [1] = 0, + }; + int ret; + + ret = rave_sp_exec(sp, cmd, sizeof(cmd), &status->firmware_version, + sizeof(status->firmware_version)); + if (ret) + return ret; + + cmd[0] = RAVE_SP_CMD_GET_BOOTLOADER_VERSION; + return rave_sp_exec(sp, cmd, sizeof(cmd), &status->bootloader_version, + sizeof(status->bootloader_version)); +} + +static int rave_sp_get_status(struct rave_sp *sp) +{ + struct device *dev = &sp->serdev->dev; struct rave_sp_status status; const char *version; int ret; - ret = rave_sp_exec(sp, cmd, sizeof(cmd), &status, sizeof(status)); + ret = sp->variant->cmd.get_status(sp, &status); if (ret) return ret; @@ -707,9 +728,10 @@ static const struct rave_sp_checksum rave_sp_checksum_ccitt = { }; static const struct rave_sp_variant rave_sp_legacy = { - .checksum = &rave_sp_checksum_8b2c, + .checksum = &rave_sp_checksum_ccitt, .cmd = { .translate = rave_sp_default_cmd_translate, + .get_status = rave_sp_emulated_get_status, }, }; @@ -717,6 +739,7 @@ static const struct rave_sp_variant rave_sp_rdu1 = { .checksum = &rave_sp_checksum_8b2c, .cmd = { .translate = rave_sp_rdu1_cmd_translate, + .get_status = rave_sp_rdu1_get_status, }, }; @@ -724,6 +747,7 @@ static const struct rave_sp_variant rave_sp_rdu2 = { .checksum = &rave_sp_checksum_ccitt, .cmd = { .translate = rave_sp_rdu2_cmd_translate, + .get_status = rave_sp_emulated_get_status, }, }; @@ -776,6 +800,13 @@ static int rave_sp_probe(struct serdev_device *serdev) return ret; serdev_device_set_baudrate(serdev, baud); + serdev_device_set_flow_control(serdev, false); + + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); + if (ret) { + dev_err(dev, "Failed to set parity\n"); + return ret; + } ret = rave_sp_get_status(sp); if (ret) { diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c new file mode 100644 index 000000000000..75c8ec659547 --- /dev/null +++ b/drivers/mfd/rohm-bd718x7.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Copyright (C) 2018 ROHM Semiconductors +// +// ROHM BD71837MWV PMIC driver +// +// Datasheet available from +// https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e + +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/mfd/rohm-bd718x7.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/regmap.h> + +/* + * gpio_keys.h requires definiton of bool. It is brought in + * by above includes. Keep this as last until gpio_keys.h gets fixed. + */ +#include <linux/gpio_keys.h> + +static const u8 supported_revisions[] = { 0xA2 /* BD71837 */ }; + +static struct gpio_keys_button button = { + .code = KEY_POWER, + .gpio = -1, + .type = EV_KEY, +}; + +static struct gpio_keys_platform_data bd718xx_powerkey_data = { + .buttons = &button, + .nbuttons = 1, + .name = "bd718xx-pwrkey", +}; + +static struct mfd_cell bd71837_mfd_cells[] = { + { + .name = "gpio-keys", + .platform_data = &bd718xx_powerkey_data, + .pdata_size = sizeof(bd718xx_powerkey_data), + }, + { .name = "bd71837-clk", }, + { .name = "bd71837-pmic", }, +}; + +static const struct regmap_irq bd71837_irqs[] = { + REGMAP_IRQ_REG(BD71837_INT_SWRST, 0, BD71837_INT_SWRST_MASK), + REGMAP_IRQ_REG(BD71837_INT_PWRBTN_S, 0, BD71837_INT_PWRBTN_S_MASK), + REGMAP_IRQ_REG(BD71837_INT_PWRBTN_L, 0, BD71837_INT_PWRBTN_L_MASK), + REGMAP_IRQ_REG(BD71837_INT_PWRBTN, 0, BD71837_INT_PWRBTN_MASK), + REGMAP_IRQ_REG(BD71837_INT_WDOG, 0, BD71837_INT_WDOG_MASK), + REGMAP_IRQ_REG(BD71837_INT_ON_REQ, 0, BD71837_INT_ON_REQ_MASK), + REGMAP_IRQ_REG(BD71837_INT_STBY_REQ, 0, BD71837_INT_STBY_REQ_MASK), +}; + +static struct regmap_irq_chip bd71837_irq_chip = { + .name = "bd71837-irq", + .irqs = bd71837_irqs, + .num_irqs = ARRAY_SIZE(bd71837_irqs), + .num_regs = 1, + .irq_reg_stride = 1, + .status_base = BD71837_REG_IRQ, + .mask_base = BD71837_REG_MIRQ, + .ack_base = BD71837_REG_IRQ, + .init_ack_masked = true, + .mask_invert = false, +}; + +static const struct regmap_range pmic_status_range = { + .range_min = BD71837_REG_IRQ, + .range_max = BD71837_REG_POW_STATE, +}; + +static const struct regmap_access_table volatile_regs = { + .yes_ranges = &pmic_status_range, + .n_yes_ranges = 1, +}; + +static const struct regmap_config bd71837_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &volatile_regs, + .max_register = BD71837_MAX_REGISTER - 1, + .cache_type = REGCACHE_RBTREE, +}; + +static int bd71837_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct bd71837 *bd71837; + int ret, i; + unsigned int val; + + bd71837 = devm_kzalloc(&i2c->dev, sizeof(struct bd71837), GFP_KERNEL); + + if (!bd71837) + return -ENOMEM; + + bd71837->chip_irq = i2c->irq; + + if (!bd71837->chip_irq) { + dev_err(&i2c->dev, "No IRQ configured\n"); + return -EINVAL; + } + + bd71837->dev = &i2c->dev; + dev_set_drvdata(&i2c->dev, bd71837); + + bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config); + if (IS_ERR(bd71837->regmap)) { + dev_err(&i2c->dev, "regmap initialization failed\n"); + return PTR_ERR(bd71837->regmap); + } + + ret = regmap_read(bd71837->regmap, BD71837_REG_REV, &val); + if (ret) { + dev_err(&i2c->dev, "Read BD71837_REG_DEVICE failed\n"); + return ret; + } + for (i = 0; i < ARRAY_SIZE(supported_revisions); i++) + if (supported_revisions[i] == val) + break; + + if (i == ARRAY_SIZE(supported_revisions)) { + dev_err(&i2c->dev, "Unsupported chip revision\n"); + return -ENODEV; + } + + ret = devm_regmap_add_irq_chip(&i2c->dev, bd71837->regmap, + bd71837->chip_irq, IRQF_ONESHOT, 0, + &bd71837_irq_chip, &bd71837->irq_data); + if (ret) { + dev_err(&i2c->dev, "Failed to add irq_chip\n"); + return ret; + } + + /* Configure short press to 10 milliseconds */ + ret = regmap_update_bits(bd71837->regmap, + BD71837_REG_PWRONCONFIG0, + BD718XX_PWRBTN_PRESS_DURATION_MASK, + BD718XX_PWRBTN_SHORT_PRESS_10MS); + if (ret) { + dev_err(&i2c->dev, + "Failed to configure button short press timeout\n"); + return ret; + } + + /* Configure long press to 10 seconds */ + ret = regmap_update_bits(bd71837->regmap, + BD71837_REG_PWRONCONFIG1, + BD718XX_PWRBTN_PRESS_DURATION_MASK, + BD718XX_PWRBTN_LONG_PRESS_10S); + + if (ret) { + dev_err(&i2c->dev, + "Failed to configure button long press timeout\n"); + return ret; + } + + ret = regmap_irq_get_virq(bd71837->irq_data, BD71837_INT_PWRBTN_S); + + if (ret < 0) { + dev_err(&i2c->dev, "Failed to get the IRQ\n"); + return ret; + } + + button.irq = ret; + + ret = devm_mfd_add_devices(bd71837->dev, PLATFORM_DEVID_AUTO, + bd71837_mfd_cells, + ARRAY_SIZE(bd71837_mfd_cells), NULL, 0, + regmap_irq_get_domain(bd71837->irq_data)); + if (ret) + dev_err(&i2c->dev, "Failed to create subdevices\n"); + + return ret; +} + +static const struct of_device_id bd71837_of_match[] = { + { .compatible = "rohm,bd71837", }, + { } +}; +MODULE_DEVICE_TABLE(of, bd71837_of_match); + +static struct i2c_driver bd71837_i2c_driver = { + .driver = { + .name = "rohm-bd718x7", + .of_match_table = bd71837_of_match, + }, + .probe = bd71837_i2c_probe, +}; + +static int __init bd71837_i2c_init(void) +{ + return i2c_add_driver(&bd71837_i2c_driver); +} + +/* Initialise early so consumer devices can complete system boot */ +subsys_initcall(bd71837_i2c_init); + +static void __exit bd71837_i2c_exit(void) +{ + i2c_del_driver(&bd71837_i2c_driver); +} +module_exit(bd71837_i2c_exit); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("ROHM BD71837 Power Management IC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index ca6b80d08ffc..9613b4257302 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -146,6 +146,7 @@ static const struct of_device_id sec_dt_match[] = { /* Sentinel */ }, }; +MODULE_DEVICE_TABLE(of, sec_dt_match); #endif static bool s2mpa01_volatile(struct device *dev, unsigned int reg) diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 2a87b0d2f21f..a530972c5a7e 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -715,6 +715,7 @@ sm501_create_subdev(struct sm501_devdata *sm, char *name, smdev->pdev.name = name; smdev->pdev.id = sm->pdev_id; smdev->pdev.dev.parent = sm->dev; + smdev->pdev.dev.coherent_dma_mask = 0xffffffff; if (res_count) { smdev->pdev.resource = (struct resource *)(smdev+1); diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 47012c0899cd..7a30546880a4 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -209,14 +209,13 @@ static int ti_tscadc_probe(struct platform_device *pdev) * The TSC_ADC_SS controller design assumes the OCP clock is * at least 6x faster than the ADC clock. */ - clk = clk_get(&pdev->dev, "adc_tsc_fck"); + clk = devm_clk_get(&pdev->dev, "adc_tsc_fck"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get TSC fck\n"); err = PTR_ERR(clk); goto err_disable_clk; } clock_rate = clk_get_rate(clk); - clk_put(clk); tscadc->clk_div = clock_rate / ADC_CLK; /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 5d5888ee2966..22bd6525e09c 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -302,6 +302,10 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) pdata->lineout2fb = true; + pdata->spkmode_pu = of_property_read_bool(np, "wlf,spkmode-pu"); + + pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd"); + pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0); if (pdata->ldo[0].enable < 0) pdata->ldo[0].enable = 0; @@ -513,14 +517,15 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) break; default: dev_err(wm8994->dev, "Unknown device type %d\n", wm8994->type); - return -EINVAL; + ret = -EINVAL; + goto err_enable; } ret = regmap_reinit_cache(wm8994->regmap, regmap_config); if (ret != 0) { dev_err(wm8994->dev, "Failed to reinit register cache: %d\n", ret); - return ret; + goto err_enable; } /* Explicitly put the device into reset in case regulators @@ -531,7 +536,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET)); if (ret != 0) { dev_err(wm8994->dev, "Failed to reset device: %d\n", ret); - return ret; + goto err_enable; } if (regmap_patch) { @@ -540,7 +545,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) if (ret != 0) { dev_err(wm8994->dev, "Failed to register patch: %d\n", ret); - goto err; + goto err_enable; } } @@ -559,6 +564,8 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) if (pdata->spkmode_pu) pulls |= WM8994_SPKMODE_PU; + if (pdata->csnaddr_pd) + pulls |= WM8994_CSNADDR_PD; /* Disable unneeded pulls */ wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 4d4acf763b65..2c43fd09d602 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -16,7 +16,6 @@ #include <linux/gfp.h> static DEFINE_IDA(cb710_ida); -static DEFINE_SPINLOCK(cb710_ida_lock); void cb710_pci_update_config_reg(struct pci_dev *pdev, int reg, uint32_t mask, uint32_t xor) @@ -205,7 +204,6 @@ static int cb710_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct cb710_chip *chip; - unsigned long flags; u32 val; int err; int n = 0; @@ -256,18 +254,10 @@ static int cb710_probe(struct pci_dev *pdev, if (err) return err; - do { - if (!ida_pre_get(&cb710_ida, GFP_KERNEL)) - return -ENOMEM; - - spin_lock_irqsave(&cb710_ida_lock, flags); - err = ida_get_new(&cb710_ida, &chip->platform_id); - spin_unlock_irqrestore(&cb710_ida_lock, flags); - - if (err && err != -EAGAIN) - return err; - } while (err); - + err = ida_alloc(&cb710_ida, GFP_KERNEL); + if (err < 0) + return err; + chip->platform_id = err; dev_info(&pdev->dev, "id %d, IO 0x%p, IRQ %d\n", chip->platform_id, chip->iobase, pdev->irq); @@ -308,7 +298,6 @@ unreg_mmc: static void cb710_remove_one(struct pci_dev *pdev) { struct cb710_chip *chip = pci_get_drvdata(pdev); - unsigned long flags; cb710_unregister_slot(chip, CB710_SLOT_SM); cb710_unregister_slot(chip, CB710_SLOT_MS); @@ -317,9 +306,7 @@ static void cb710_remove_one(struct pci_dev *pdev) BUG_ON(atomic_read(&chip->slot_refs_count) != 0); #endif - spin_lock_irqsave(&cb710_ida_lock, flags); - ida_remove(&cb710_ida, chip->platform_id); - spin_unlock_irqrestore(&cb710_ida_lock, flags); + ida_free(&cb710_ida, chip->platform_id); } static const struct pci_device_id cb710_pci_tbl[] = { diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index f5cc517d1131..7e50e1d6f58c 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -478,6 +478,23 @@ static void at24_properties_to_pdata(struct device *dev, if (device_property_present(dev, "no-read-rollover")) chip->flags |= AT24_FLAG_NO_RDROL; + err = device_property_read_u32(dev, "address-width", &val); + if (!err) { + switch (val) { + case 8: + if (chip->flags & AT24_FLAG_ADDR16) + dev_warn(dev, "Override address width to be 8, while default is 16\n"); + chip->flags &= ~AT24_FLAG_ADDR16; + break; + case 16: + chip->flags |= AT24_FLAG_ADDR16; + break; + default: + dev_warn(dev, "Bad \"address-width\" property: %u\n", + val); + } + } + err = device_property_read_u32(dev, "size", &val); if (!err) chip->byte_len = val; diff --git a/drivers/misc/mic/scif/scif_dma.c b/drivers/misc/mic/scif/scif_dma.c index 63d6246d6dff..6369aeaa7056 100644 --- a/drivers/misc/mic/scif/scif_dma.c +++ b/drivers/misc/mic/scif/scif_dma.c @@ -200,15 +200,18 @@ static void scif_mmu_notifier_release(struct mmu_notifier *mn, schedule_work(&scif_info.misc_work); } -static void scif_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, +static int scif_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end, + bool blockable) { struct scif_mmu_notif *mmn; mmn = container_of(mn, struct scif_mmu_notif, ep_mmu_notifier); scif_rma_destroy_tcw(mmn, start, end - start); + + return 0; } static void scif_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c index a3454eb56fbf..be28f05bfafa 100644 --- a/drivers/misc/sgi-gru/grutlbpurge.c +++ b/drivers/misc/sgi-gru/grutlbpurge.c @@ -219,9 +219,10 @@ void gru_flush_all_tlb(struct gru_state *gru) /* * MMUOPS notifier callout functions */ -static void gru_invalidate_range_start(struct mmu_notifier *mn, +static int gru_invalidate_range_start(struct mmu_notifier *mn, struct mm_struct *mm, - unsigned long start, unsigned long end) + unsigned long start, unsigned long end, + bool blockable) { struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, ms_notifier); @@ -231,6 +232,8 @@ static void gru_invalidate_range_start(struct mmu_notifier *mn, gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx, act %d\n", gms, start, end, atomic_read(&gms->ms_range_active)); gru_flush_tlb_range(gms, start, end - start); + + return 0; } static void gru_invalidate_range_end(struct mmu_notifier *mn, diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 45c329694a5e..22547d7a84ea 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -367,6 +367,10 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, return count; } + /* + * We voluntarily do not take into account the skip_check flag + * as we want to make sure what we wrote was correctly written. + */ err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) return err; @@ -622,6 +626,13 @@ static int verify_mkvol_req(const struct ubi_device *ubi, req->vol_type != UBI_STATIC_VOLUME) goto bad; + if (req->flags & ~UBI_VOL_VALID_FLGS) + goto bad; + + if (req->flags & UBI_VOL_SKIP_CRC_CHECK_FLG && + req->vol_type != UBI_STATIC_VOLUME) + goto bad; + if (req->alignment > ubi->leb_size) goto bad; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d4b2e8744498..e9e9ecbcedcc 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -202,7 +202,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) desc->mode = mode; mutex_lock(&ubi->ckvol_mutex); - if (!vol->checked) { + if (!vol->checked && !vol->skip_check) { /* This is the first open - check the volume */ err = ubi_check_volume(ubi, vol_id); if (err < 0) { diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h index 195ff8ca8211..b5fe8f82281b 100644 --- a/drivers/mtd/ubi/ubi-media.h +++ b/drivers/mtd/ubi/ubi-media.h @@ -45,6 +45,11 @@ enum { * Volume flags used in the volume table record. * * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume + * @UBI_VTBL_SKIP_CRC_CHECK_FLG: skip the CRC check done on a static volume at + * open time. Should only be set on volumes that + * are used by upper layers doing this kind of + * check. Main use-case for this flag is + * boot-time reduction * * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume * table. UBI automatically re-sizes the volume which has this flag and makes @@ -76,6 +81,7 @@ enum { */ enum { UBI_VTBL_AUTORESIZE_FLG = 0x01, + UBI_VTBL_SKIP_CRC_CHECK_FLG = 0x02, }; /* diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index f5ba97c46160..d47b9e436e67 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -327,6 +327,9 @@ struct ubi_eba_leb_desc { * atomic LEB change * * @eba_tbl: EBA table of this volume (LEB->PEB mapping) + * @skip_check: %1 if CRC check of this static volume should be skipped. + * Directly reflects the presence of the + * %UBI_VTBL_SKIP_CRC_CHECK_FLG flag in the vtbl entry * @checked: %1 if this static volume was checked * @corrupted: %1 if the volume is corrupted (static volumes only) * @upd_marker: %1 if the update marker is set for this volume @@ -374,6 +377,7 @@ struct ubi_volume { void *upd_buf; struct ubi_eba_table *eba_tbl; + unsigned int skip_check:1; unsigned int checked:1; unsigned int corrupted:1; unsigned int upd_marker:1; diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 0be516780e92..729588b94e41 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -174,6 +174,9 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vol->dev.class = &ubi_class; vol->dev.groups = volume_dev_groups; + if (req->flags & UBI_VOL_SKIP_CRC_CHECK_FLG) + vol->skip_check = 1; + spin_lock(&ubi->volumes_lock); if (vol_id == UBI_VOL_NUM_AUTO) { /* Find unused volume ID */ @@ -299,6 +302,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vtbl_rec.vol_type = UBI_VID_DYNAMIC; else vtbl_rec.vol_type = UBI_VID_STATIC; + + if (vol->skip_check) + vtbl_rec.flags |= UBI_VTBL_SKIP_CRC_CHECK_FLG; + memcpy(vtbl_rec.name, vol->name, vol->name_len); err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); @@ -733,6 +740,11 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) ubi_err(ubi, "bad used_bytes"); goto fail; } + + if (vol->skip_check) { + ubi_err(ubi, "bad skip_check"); + goto fail; + } } else { if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { ubi_err(ubi, "bad used_ebs"); diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 94d7a865b135..1bc82154bb18 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -560,6 +560,9 @@ static int init_volumes(struct ubi_device *ubi, vol->name[vol->name_len] = '\0'; vol->vol_id = i; + if (vtbl[i].flags & UBI_VTBL_SKIP_CRC_CHECK_FLG) + vol->skip_check = 1; + if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { /* Auto re-size flag may be set only for one volume */ if (ubi->autoresize_vol_id != -1) { @@ -579,6 +582,16 @@ static int init_volumes(struct ubi_device *ubi, reserved_pebs += vol->reserved_pebs; /* + * We use ubi->peb_count and not vol->reserved_pebs because + * we want to keep the code simple. Otherwise we'd have to + * resize/check the bitmap upon volume resize too. + * Allocating a few bytes more does not hurt. + */ + err = ubi_fastmap_init_checkmap(vol, ubi->peb_count); + if (err) + return err; + + /* * In case of dynamic volume UBI knows nothing about how many * data is stored there. So assume the whole volume is used. */ @@ -620,16 +633,6 @@ static int init_volumes(struct ubi_device *ubi, (long long)(vol->used_ebs - 1) * vol->usable_leb_size; vol->used_bytes += av->last_data_size; vol->last_eb_bytes = av->last_data_size; - - /* - * We use ubi->peb_count and not vol->reserved_pebs because - * we want to keep the code simple. Otherwise we'd have to - * resize/check the bitmap upon volume resize too. - * Allocating a few bytes more does not hurt. - */ - err = ubi_fastmap_init_checkmap(vol, ubi->peb_count); - if (err) - return err; } /* And add the layout volume */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index 139d96c5a023..092c817f8f11 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -110,16 +110,14 @@ static int bnxt_tc_parse_actions(struct bnxt *bp, struct tcf_exts *tc_exts) { const struct tc_action *tc_act; - LIST_HEAD(tc_actions); - int rc; + int i, rc; if (!tcf_exts_has_actions(tc_exts)) { netdev_info(bp->dev, "no actions"); return -EINVAL; } - tcf_exts_to_list(tc_exts, &tc_actions); - list_for_each_entry(tc_act, &tc_actions, list) { + tcf_exts_for_each_action(i, tc_act, tc_exts) { /* Drop action */ if (is_tcf_gact_shot(tc_act)) { actions->flags |= BNXT_TC_ACTION_FLAG_DROP; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index dc09f9a8a49b..c6707ea2d751 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -482,11 +482,6 @@ static int macb_mii_probe(struct net_device *dev) if (np) { if (of_phy_is_fixed_link(np)) { - if (of_phy_register_fixed_link(np) < 0) { - dev_err(&bp->pdev->dev, - "broken fixed-link specification\n"); - return -ENODEV; - } bp->phy_node = of_node_get(np); } else { bp->phy_node = of_parse_phandle(np, "phy-handle", 0); @@ -569,7 +564,7 @@ static int macb_mii_init(struct macb *bp) { struct macb_platform_data *pdata; struct device_node *np; - int err; + int err = -ENXIO; /* Enable management port */ macb_writel(bp, NCR, MACB_BIT(MPE)); @@ -592,12 +587,23 @@ static int macb_mii_init(struct macb *bp) dev_set_drvdata(&bp->dev->dev, bp->mii_bus); np = bp->pdev->dev.of_node; - if (pdata) - bp->mii_bus->phy_mask = pdata->phy_mask; + if (np && of_phy_is_fixed_link(np)) { + if (of_phy_register_fixed_link(np) < 0) { + dev_err(&bp->pdev->dev, + "broken fixed-link specification %pOF\n", np); + goto err_out_free_mdiobus; + } + + err = mdiobus_register(bp->mii_bus); + } else { + if (pdata) + bp->mii_bus->phy_mask = pdata->phy_mask; + + err = of_mdiobus_register(bp->mii_bus, np); + } - err = of_mdiobus_register(bp->mii_bus, np); if (err) - goto err_out_free_mdiobus; + goto err_out_free_fixed_link; err = macb_mii_probe(bp->dev); if (err) @@ -607,6 +613,7 @@ static int macb_mii_init(struct macb *bp) err_out_unregister_bus: mdiobus_unregister(bp->mii_bus); +err_out_free_fixed_link: if (np && of_phy_is_fixed_link(np)) of_phy_deregister_fixed_link(np); err_out_free_mdiobus: @@ -2028,14 +2035,17 @@ static void macb_reset_hw(struct macb *bp) { struct macb_queue *queue; unsigned int q; + u32 ctrl = macb_readl(bp, NCR); /* Disable RX and TX (XXX: Should we halt the transmission * more gracefully?) */ - macb_writel(bp, NCR, 0); + ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE)); /* Clear the stats registers (XXX: Update stats first?) */ - macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); + ctrl |= MACB_BIT(CLRSTAT); + + macb_writel(bp, NCR, ctrl); /* Clear all status flags */ macb_writel(bp, TSR, -1); @@ -2223,7 +2233,7 @@ static void macb_init_hw(struct macb *bp) } /* Enable TX and RX */ - macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE)); } /* The hash address register is 64 bits long and takes up two diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c index 623f73dd7738..c116f96956fe 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c @@ -417,10 +417,9 @@ static void cxgb4_process_flow_actions(struct net_device *in, struct ch_filter_specification *fs) { const struct tc_action *a; - LIST_HEAD(actions); + int i; - tcf_exts_to_list(cls->exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, cls->exts) { if (is_tcf_gact_ok(a)) { fs->action = FILTER_PASS; } else if (is_tcf_gact_shot(a)) { @@ -591,10 +590,9 @@ static int cxgb4_validate_flow_actions(struct net_device *dev, bool act_redir = false; bool act_pedit = false; bool act_vlan = false; - LIST_HEAD(actions); + int i; - tcf_exts_to_list(cls->exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, cls->exts) { if (is_tcf_gact_ok(a)) { /* Do nothing */ } else if (is_tcf_gact_shot(a)) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c index 18eb2aedd4cb..c7d2b4dc7568 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c @@ -93,14 +93,13 @@ static int fill_action_fields(struct adapter *adap, unsigned int num_actions = 0; const struct tc_action *a; struct tcf_exts *exts; - LIST_HEAD(actions); + int i; exts = cls->knode.exts; if (!tcf_exts_has_actions(exts)) return -EINVAL; - tcf_exts_to_list(exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, exts) { /* Don't allow more than one action per rule. */ if (num_actions) return -EINVAL; diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h index fa5b30f547f6..cad52bd331f7 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -220,10 +220,10 @@ struct hnae_desc_cb { /* priv data for the desc, e.g. skb when use with ip stack*/ void *priv; - u16 page_offset; - u16 reuse_flag; + u32 page_offset; + u32 length; /* length of the buffer */ - u16 length; /* length of the buffer */ + u16 reuse_flag; /* desc type, used by the ring user to mark the type of the priv data */ u16 type; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 9f2b552aee33..02a0ba20fad5 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -406,113 +406,13 @@ out_net_tx_busy: return NETDEV_TX_BUSY; } -/** - * hns_nic_get_headlen - determine size of header for RSC/LRO/GRO/FCOE - * @data: pointer to the start of the headers - * @max: total length of section to find headers in - * - * This function is meant to determine the length of headers that will - * be recognized by hardware for LRO, GRO, and RSC offloads. The main - * motivation of doing this is to only perform one pull for IPv4 TCP - * packets so that we can do basic things like calculating the gso_size - * based on the average data per packet. - **/ -static unsigned int hns_nic_get_headlen(unsigned char *data, u32 flag, - unsigned int max_size) -{ - unsigned char *network; - u8 hlen; - - /* this should never happen, but better safe than sorry */ - if (max_size < ETH_HLEN) - return max_size; - - /* initialize network frame pointer */ - network = data; - - /* set first protocol and move network header forward */ - network += ETH_HLEN; - - /* handle any vlan tag if present */ - if (hnae_get_field(flag, HNS_RXD_VLAN_M, HNS_RXD_VLAN_S) - == HNS_RX_FLAG_VLAN_PRESENT) { - if ((typeof(max_size))(network - data) > (max_size - VLAN_HLEN)) - return max_size; - - network += VLAN_HLEN; - } - - /* handle L3 protocols */ - if (hnae_get_field(flag, HNS_RXD_L3ID_M, HNS_RXD_L3ID_S) - == HNS_RX_FLAG_L3ID_IPV4) { - if ((typeof(max_size))(network - data) > - (max_size - sizeof(struct iphdr))) - return max_size; - - /* access ihl as a u8 to avoid unaligned access on ia64 */ - hlen = (network[0] & 0x0F) << 2; - - /* verify hlen meets minimum size requirements */ - if (hlen < sizeof(struct iphdr)) - return network - data; - - /* record next protocol if header is present */ - } else if (hnae_get_field(flag, HNS_RXD_L3ID_M, HNS_RXD_L3ID_S) - == HNS_RX_FLAG_L3ID_IPV6) { - if ((typeof(max_size))(network - data) > - (max_size - sizeof(struct ipv6hdr))) - return max_size; - - /* record next protocol */ - hlen = sizeof(struct ipv6hdr); - } else { - return network - data; - } - - /* relocate pointer to start of L4 header */ - network += hlen; - - /* finally sort out TCP/UDP */ - if (hnae_get_field(flag, HNS_RXD_L4ID_M, HNS_RXD_L4ID_S) - == HNS_RX_FLAG_L4ID_TCP) { - if ((typeof(max_size))(network - data) > - (max_size - sizeof(struct tcphdr))) - return max_size; - - /* access doff as a u8 to avoid unaligned access on ia64 */ - hlen = (network[12] & 0xF0) >> 2; - - /* verify hlen meets minimum size requirements */ - if (hlen < sizeof(struct tcphdr)) - return network - data; - - network += hlen; - } else if (hnae_get_field(flag, HNS_RXD_L4ID_M, HNS_RXD_L4ID_S) - == HNS_RX_FLAG_L4ID_UDP) { - if ((typeof(max_size))(network - data) > - (max_size - sizeof(struct udphdr))) - return max_size; - - network += sizeof(struct udphdr); - } - - /* If everything has gone correctly network should be the - * data section of the packet and will be the end of the header. - * If not then it probably represents the end of the last recognized - * header. - */ - if ((typeof(max_size))(network - data) < max_size) - return network - data; - else - return max_size; -} - static void hns_nic_reuse_page(struct sk_buff *skb, int i, struct hnae_ring *ring, int pull_len, struct hnae_desc_cb *desc_cb) { struct hnae_desc *desc; - int truesize, size; + u32 truesize; + int size; int last_offset; bool twobufs; @@ -530,7 +430,7 @@ static void hns_nic_reuse_page(struct sk_buff *skb, int i, } skb_add_rx_frag(skb, i, desc_cb->priv, desc_cb->page_offset + pull_len, - size - pull_len, truesize - pull_len); + size - pull_len, truesize); /* avoid re-using remote pages,flag default unreuse */ if (unlikely(page_to_nid(desc_cb->priv) != numa_node_id())) @@ -695,7 +595,7 @@ static int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data, } else { ring->stats.seg_pkt_cnt++; - pull_len = hns_nic_get_headlen(va, bnum_flag, HNS_RX_HEAD_SIZE); + pull_len = eth_get_headlen(va, HNS_RX_HEAD_SIZE); memcpy(__skb_put(skb, pull_len), va, ALIGN(pull_len, sizeof(long))); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 3554dca7a680..955c4ab18b03 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2019,7 +2019,8 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i, struct hns3_desc_cb *desc_cb) { struct hns3_desc *desc; - int truesize, size; + u32 truesize; + int size; int last_offset; bool twobufs; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index a02a96aee2a2..cb450d7ec8c1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -284,11 +284,11 @@ struct hns3_desc_cb { /* priv data for the desc, e.g. skb when use with ip stack*/ void *priv; - u16 page_offset; - u16 reuse_flag; - + u32 page_offset; u32 length; /* length of the buffer */ + u16 reuse_flag; + /* desc type, used by the ring user to mark the type of the priv data */ u16 type; }; diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index bdb3f8e65ed4..2569a168334c 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -624,14 +624,14 @@ static int e1000_set_ringparam(struct net_device *netdev, adapter->tx_ring = tx_old; e1000_free_all_rx_resources(adapter); e1000_free_all_tx_resources(adapter); - kfree(tx_old); - kfree(rx_old); adapter->rx_ring = rxdr; adapter->tx_ring = txdr; err = e1000_up(adapter); if (err) goto err_setup; } + kfree(tx_old); + kfree(rx_old); clear_bit(__E1000_RESETTING, &adapter->flags); return 0; @@ -644,7 +644,8 @@ err_setup_rx: err_alloc_rx: kfree(txdr); err_alloc_tx: - e1000_up(adapter); + if (netif_running(adapter->netdev)) + e1000_up(adapter); err_setup: clear_bit(__E1000_RESETTING, &adapter->flags); return err; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index abcd096ede14..5ff6caa83948 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2013,7 +2013,7 @@ static void i40e_get_stat_strings(struct net_device *netdev, u8 *data) for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) i40e_add_stat_strings(&data, i40e_gstrings_pfc_stats, i); - WARN_ONCE(p - data != i40e_get_stats_count(netdev) * ETH_GSTRING_LEN, + WARN_ONCE(data - p != i40e_get_stats_count(netdev) * ETH_GSTRING_LEN, "stat strings count mismatch!"); } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f2c622e78802..ac685ad4d877 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5122,15 +5122,17 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc, u8 *bw_share) { struct i40e_aqc_configure_vsi_tc_bw_data bw_data; + struct i40e_pf *pf = vsi->back; i40e_status ret; int i; - if (vsi->back->flags & I40E_FLAG_TC_MQPRIO) + /* There is no need to reset BW when mqprio mode is on. */ + if (pf->flags & I40E_FLAG_TC_MQPRIO) return 0; - if (!vsi->mqprio_qopt.qopt.hw) { + if (!vsi->mqprio_qopt.qopt.hw && !(pf->flags & I40E_FLAG_DCB_ENABLED)) { ret = i40e_set_bw_limit(vsi, vsi->seid, 0); if (ret) - dev_info(&vsi->back->pdev->dev, + dev_info(&pf->pdev->dev, "Failed to reset tx rate for vsi->seid %u\n", vsi->seid); return ret; @@ -5139,12 +5141,11 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc, for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) bw_data.tc_bw_credits[i] = bw_share[i]; - ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data, - NULL); + ret = i40e_aq_config_vsi_tc_bw(&pf->hw, vsi->seid, &bw_data, NULL); if (ret) { - dev_info(&vsi->back->pdev->dev, + dev_info(&pf->pdev->dev, "AQ command Config VSI BW allocation per TC failed = %d\n", - vsi->back->hw.aq.asq_last_status); + pf->hw.aq.asq_last_status); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index d8b5fff581e7..868f4a1d0f72 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -89,6 +89,13 @@ extern const char ice_drv_ver[]; #define ice_for_each_rxq(vsi, i) \ for ((i) = 0; (i) < (vsi)->num_rxq; (i)++) +/* Macros for each allocated tx/rx ring whether used or not in a VSI */ +#define ice_for_each_alloc_txq(vsi, i) \ + for ((i) = 0; (i) < (vsi)->alloc_txq; (i)++) + +#define ice_for_each_alloc_rxq(vsi, i) \ + for ((i) = 0; (i) < (vsi)->alloc_rxq; (i)++) + struct ice_tc_info { u16 qoffset; u16 qcount; @@ -189,9 +196,9 @@ struct ice_vsi { struct list_head tmp_sync_list; /* MAC filters to be synced */ struct list_head tmp_unsync_list; /* MAC filters to be unsynced */ - bool irqs_ready; - bool current_isup; /* Sync 'link up' logging */ - bool stat_offsets_loaded; + u8 irqs_ready; + u8 current_isup; /* Sync 'link up' logging */ + u8 stat_offsets_loaded; /* queue information */ u8 tx_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ @@ -262,7 +269,7 @@ struct ice_pf { struct ice_hw_port_stats stats; struct ice_hw_port_stats stats_prev; struct ice_hw hw; - bool stat_prev_loaded; /* has previous stats been loaded */ + u8 stat_prev_loaded; /* has previous stats been loaded */ char int_name[ICE_INT_NAME_STR_LEN]; }; diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 7541ec2270b3..a0614f472658 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -329,19 +329,19 @@ struct ice_aqc_vsi_props { /* VLAN section */ __le16 pvid; /* VLANS include priority bits */ u8 pvlan_reserved[2]; - u8 port_vlan_flags; -#define ICE_AQ_VSI_PVLAN_MODE_S 0 -#define ICE_AQ_VSI_PVLAN_MODE_M (0x3 << ICE_AQ_VSI_PVLAN_MODE_S) -#define ICE_AQ_VSI_PVLAN_MODE_UNTAGGED 0x1 -#define ICE_AQ_VSI_PVLAN_MODE_TAGGED 0x2 -#define ICE_AQ_VSI_PVLAN_MODE_ALL 0x3 + u8 vlan_flags; +#define ICE_AQ_VSI_VLAN_MODE_S 0 +#define ICE_AQ_VSI_VLAN_MODE_M (0x3 << ICE_AQ_VSI_VLAN_MODE_S) +#define ICE_AQ_VSI_VLAN_MODE_UNTAGGED 0x1 +#define ICE_AQ_VSI_VLAN_MODE_TAGGED 0x2 +#define ICE_AQ_VSI_VLAN_MODE_ALL 0x3 #define ICE_AQ_VSI_PVLAN_INSERT_PVID BIT(2) -#define ICE_AQ_VSI_PVLAN_EMOD_S 3 -#define ICE_AQ_VSI_PVLAN_EMOD_M (0x3 << ICE_AQ_VSI_PVLAN_EMOD_S) -#define ICE_AQ_VSI_PVLAN_EMOD_STR_BOTH (0x0 << ICE_AQ_VSI_PVLAN_EMOD_S) -#define ICE_AQ_VSI_PVLAN_EMOD_STR_UP (0x1 << ICE_AQ_VSI_PVLAN_EMOD_S) -#define ICE_AQ_VSI_PVLAN_EMOD_STR (0x2 << ICE_AQ_VSI_PVLAN_EMOD_S) -#define ICE_AQ_VSI_PVLAN_EMOD_NOTHING (0x3 << ICE_AQ_VSI_PVLAN_EMOD_S) +#define ICE_AQ_VSI_VLAN_EMOD_S 3 +#define ICE_AQ_VSI_VLAN_EMOD_M (0x3 << ICE_AQ_VSI_VLAN_EMOD_S) +#define ICE_AQ_VSI_VLAN_EMOD_STR_BOTH (0x0 << ICE_AQ_VSI_VLAN_EMOD_S) +#define ICE_AQ_VSI_VLAN_EMOD_STR_UP (0x1 << ICE_AQ_VSI_VLAN_EMOD_S) +#define ICE_AQ_VSI_VLAN_EMOD_STR (0x2 << ICE_AQ_VSI_VLAN_EMOD_S) +#define ICE_AQ_VSI_VLAN_EMOD_NOTHING (0x3 << ICE_AQ_VSI_VLAN_EMOD_S) u8 pvlan_reserved2[3]; /* ingress egress up sections */ __le32 ingress_table; /* bitmap, 3 bits per up */ @@ -594,6 +594,7 @@ struct ice_sw_rule_lg_act { #define ICE_LG_ACT_GENERIC_OFFSET_M (0x7 << ICE_LG_ACT_GENERIC_OFFSET_S) #define ICE_LG_ACT_GENERIC_PRIORITY_S 22 #define ICE_LG_ACT_GENERIC_PRIORITY_M (0x7 << ICE_LG_ACT_GENERIC_PRIORITY_S) +#define ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX 7 /* Action = 7 - Set Stat count */ #define ICE_LG_ACT_STAT_COUNT 0x7 diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 71d032cc5fa7..661beea6af79 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -45,6 +45,9 @@ static enum ice_status ice_set_mac_type(struct ice_hw *hw) /** * ice_clear_pf_cfg - Clear PF configuration * @hw: pointer to the hardware structure + * + * Clears any existing PF configuration (VSIs, VSI lists, switch rules, port + * configuration, flow director filters, etc.). */ enum ice_status ice_clear_pf_cfg(struct ice_hw *hw) { @@ -1483,7 +1486,7 @@ enum ice_status ice_get_link_status(struct ice_port_info *pi, bool *link_up) struct ice_phy_info *phy_info; enum ice_status status = 0; - if (!pi) + if (!pi || !link_up) return ICE_ERR_PARAM; phy_info = &pi->phy; @@ -1619,20 +1622,23 @@ __ice_aq_get_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut, } /* LUT size is only valid for Global and PF table types */ - if (lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128) { - flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128_FLAG << - ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) & - ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M; - } else if (lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512) { + switch (lut_size) { + case ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128: + break; + case ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512: flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512_FLAG << ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) & ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M; - } else if ((lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K) && - (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF)) { - flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG << - ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) & - ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M; - } else { + break; + case ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K: + if (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF) { + flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG << + ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) & + ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M; + break; + } + /* fall-through */ + default: status = ICE_ERR_PARAM; goto ice_aq_get_set_rss_lut_exit; } diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 7c511f144ed6..62be72fdc8f3 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -597,10 +597,14 @@ static enum ice_status ice_init_check_adminq(struct ice_hw *hw) return 0; init_ctrlq_free_rq: - ice_shutdown_rq(hw, cq); - ice_shutdown_sq(hw, cq); - mutex_destroy(&cq->sq_lock); - mutex_destroy(&cq->rq_lock); + if (cq->rq.head) { + ice_shutdown_rq(hw, cq); + mutex_destroy(&cq->rq_lock); + } + if (cq->sq.head) { + ice_shutdown_sq(hw, cq); + mutex_destroy(&cq->sq_lock); + } return status; } @@ -706,10 +710,14 @@ static void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type) return; } - ice_shutdown_sq(hw, cq); - ice_shutdown_rq(hw, cq); - mutex_destroy(&cq->sq_lock); - mutex_destroy(&cq->rq_lock); + if (cq->sq.head) { + ice_shutdown_sq(hw, cq); + mutex_destroy(&cq->sq_lock); + } + if (cq->rq.head) { + ice_shutdown_rq(hw, cq); + mutex_destroy(&cq->rq_lock); + } } /** @@ -1057,8 +1065,11 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, clean_rq_elem_out: /* Set pending if needed, unlock and return */ - if (pending) + if (pending) { + /* re-read HW head to calculate actual pending messages */ + ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask); *pending = (u16)((ntc > ntu ? cq->rq.count : 0) + (ntu - ntc)); + } clean_rq_elem_err: mutex_unlock(&cq->rq_lock); diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 1db304c01d10..c71a9b528d6d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -26,7 +26,7 @@ static int ice_q_stats_len(struct net_device *netdev) { struct ice_netdev_priv *np = netdev_priv(netdev); - return ((np->vsi->num_txq + np->vsi->num_rxq) * + return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) * (sizeof(struct ice_q_stats) / sizeof(u64))); } @@ -218,7 +218,7 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) p += ETH_GSTRING_LEN; } - ice_for_each_txq(vsi, i) { + ice_for_each_alloc_txq(vsi, i) { snprintf(p, ETH_GSTRING_LEN, "tx-queue-%u.tx_packets", i); p += ETH_GSTRING_LEN; @@ -226,7 +226,7 @@ static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) p += ETH_GSTRING_LEN; } - ice_for_each_rxq(vsi, i) { + ice_for_each_alloc_rxq(vsi, i) { snprintf(p, ETH_GSTRING_LEN, "rx-queue-%u.rx_packets", i); p += ETH_GSTRING_LEN; @@ -253,6 +253,24 @@ static int ice_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { case ETH_SS_STATS: + /* The number (and order) of strings reported *must* remain + * constant for a given netdevice. This function must not + * report a different number based on run time parameters + * (such as the number of queues in use, or the setting of + * a private ethtool flag). This is due to the nature of the + * ethtool stats API. + * + * User space programs such as ethtool must make 3 separate + * ioctl requests, one for size, one for the strings, and + * finally one for the stats. Since these cross into + * user space, changes to the number or size could result in + * undefined memory access or incorrect string<->value + * correlations for statistics. + * + * Even if it appears to be safe, changes to the size or + * order of strings will suffer from race conditions and are + * not safe. + */ return ICE_ALL_STATS_LEN(netdev); default: return -EOPNOTSUPP; @@ -280,18 +298,26 @@ ice_get_ethtool_stats(struct net_device *netdev, /* populate per queue stats */ rcu_read_lock(); - ice_for_each_txq(vsi, j) { + ice_for_each_alloc_txq(vsi, j) { ring = READ_ONCE(vsi->tx_rings[j]); - if (!ring) - continue; - data[i++] = ring->stats.pkts; - data[i++] = ring->stats.bytes; + if (ring) { + data[i++] = ring->stats.pkts; + data[i++] = ring->stats.bytes; + } else { + data[i++] = 0; + data[i++] = 0; + } } - ice_for_each_rxq(vsi, j) { + ice_for_each_alloc_rxq(vsi, j) { ring = READ_ONCE(vsi->rx_rings[j]); - data[i++] = ring->stats.pkts; - data[i++] = ring->stats.bytes; + if (ring) { + data[i++] = ring->stats.pkts; + data[i++] = ring->stats.bytes; + } else { + data[i++] = 0; + data[i++] = 0; + } } rcu_read_unlock(); @@ -519,7 +545,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) goto done; } - for (i = 0; i < vsi->num_txq; i++) { + for (i = 0; i < vsi->alloc_txq; i++) { /* clone ring and setup updated count */ tx_rings[i] = *vsi->tx_rings[i]; tx_rings[i].count = new_tx_cnt; @@ -551,7 +577,7 @@ process_rx: goto done; } - for (i = 0; i < vsi->num_rxq; i++) { + for (i = 0; i < vsi->alloc_rxq; i++) { /* clone ring and setup updated count */ rx_rings[i] = *vsi->rx_rings[i]; rx_rings[i].count = new_rx_cnt; diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 499904874b3f..6076fc87df9d 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -121,10 +121,6 @@ #define PFINT_FW_CTL_CAUSE_ENA_S 30 #define PFINT_FW_CTL_CAUSE_ENA_M BIT(PFINT_FW_CTL_CAUSE_ENA_S) #define PFINT_OICR 0x0016CA00 -#define PFINT_OICR_HLP_RDY_S 14 -#define PFINT_OICR_HLP_RDY_M BIT(PFINT_OICR_HLP_RDY_S) -#define PFINT_OICR_CPM_RDY_S 15 -#define PFINT_OICR_CPM_RDY_M BIT(PFINT_OICR_CPM_RDY_S) #define PFINT_OICR_ECC_ERR_S 16 #define PFINT_OICR_ECC_ERR_M BIT(PFINT_OICR_ECC_ERR_S) #define PFINT_OICR_MAL_DETECT_S 19 @@ -133,10 +129,6 @@ #define PFINT_OICR_GRST_M BIT(PFINT_OICR_GRST_S) #define PFINT_OICR_PCI_EXCEPTION_S 21 #define PFINT_OICR_PCI_EXCEPTION_M BIT(PFINT_OICR_PCI_EXCEPTION_S) -#define PFINT_OICR_GPIO_S 22 -#define PFINT_OICR_GPIO_M BIT(PFINT_OICR_GPIO_S) -#define PFINT_OICR_STORM_DETECT_S 24 -#define PFINT_OICR_STORM_DETECT_M BIT(PFINT_OICR_STORM_DETECT_S) #define PFINT_OICR_HMC_ERR_S 26 #define PFINT_OICR_HMC_ERR_M BIT(PFINT_OICR_HMC_ERR_S) #define PFINT_OICR_PE_CRITERR_S 28 diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index d23a91665b46..068dbc740b76 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -265,6 +265,7 @@ enum ice_rx_flex_desc_status_error_0_bits { struct ice_rlan_ctx { u16 head; u16 cpuid; /* bigger than needed, see above for reason */ +#define ICE_RLAN_BASE_S 7 u64 base; u16 qlen; #define ICE_RLAN_CTX_DBUF_S 7 diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 5299caf55a7f..f1e80eed2fd6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -901,7 +901,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) case ice_aqc_opc_get_link_status: if (ice_handle_link_event(pf)) dev_err(&pf->pdev->dev, - "Could not handle link event"); + "Could not handle link event\n"); break; default: dev_dbg(&pf->pdev->dev, @@ -917,13 +917,27 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) } /** + * ice_ctrlq_pending - check if there is a difference between ntc and ntu + * @hw: pointer to hardware info + * @cq: control queue information + * + * returns true if there are pending messages in a queue, false if there aren't + */ +static bool ice_ctrlq_pending(struct ice_hw *hw, struct ice_ctl_q_info *cq) +{ + u16 ntu; + + ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask); + return cq->rq.next_to_clean != ntu; +} + +/** * ice_clean_adminq_subtask - clean the AdminQ rings * @pf: board private structure */ static void ice_clean_adminq_subtask(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; - u32 val; if (!test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state)) return; @@ -933,9 +947,13 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf) clear_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state); - /* re-enable Admin queue interrupt causes */ - val = rd32(hw, PFINT_FW_CTL); - wr32(hw, PFINT_FW_CTL, (val | PFINT_FW_CTL_CAUSE_ENA_M)); + /* There might be a situation where new messages arrive to a control + * queue between processing the last message and clearing the + * EVENT_PENDING bit. So before exiting, check queue head again (using + * ice_ctrlq_pending) and process new messages if any. + */ + if (ice_ctrlq_pending(hw, &hw->adminq)) + __ice_clean_ctrlq(pf, ICE_CTL_Q_ADMIN); ice_flush(hw); } @@ -1295,11 +1313,8 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) qcount = numq_tc; } - /* find higher power-of-2 of qcount */ - pow = ilog2(qcount); - - if (!is_power_of_2(qcount)) - pow++; + /* find the (rounded up) power-of-2 of qcount */ + pow = order_base_2(qcount); for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) { if (!(vsi->tc_cfg.ena_tc & BIT(i))) { @@ -1352,14 +1367,15 @@ static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt) ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; /* Traffic from VSI can be sent to LAN */ ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; - /* Allow all packets untagged/tagged */ - ctxt->info.port_vlan_flags = ((ICE_AQ_VSI_PVLAN_MODE_ALL & - ICE_AQ_VSI_PVLAN_MODE_M) >> - ICE_AQ_VSI_PVLAN_MODE_S); - /* Show VLAN/UP from packets in Rx descriptors */ - ctxt->info.port_vlan_flags |= ((ICE_AQ_VSI_PVLAN_EMOD_STR_BOTH & - ICE_AQ_VSI_PVLAN_EMOD_M) >> - ICE_AQ_VSI_PVLAN_EMOD_S); + + /* By default bits 3 and 4 in vlan_flags are 0's which results in legacy + * behavior (show VLAN, DEI, and UP) in descriptor. Also, allow all + * packets untagged/tagged. + */ + ctxt->info.vlan_flags = ((ICE_AQ_VSI_VLAN_MODE_ALL & + ICE_AQ_VSI_VLAN_MODE_M) >> + ICE_AQ_VSI_VLAN_MODE_S); + /* Have 1:1 UP mapping for both ingress/egress tables */ table |= ICE_UP_TABLE_TRANSLATE(0, 0); table |= ICE_UP_TABLE_TRANSLATE(1, 1); @@ -1688,15 +1704,12 @@ static void ice_ena_misc_vector(struct ice_pf *pf) wr32(hw, PFINT_OICR_ENA, 0); /* disable all */ rd32(hw, PFINT_OICR); /* read to clear */ - val = (PFINT_OICR_HLP_RDY_M | - PFINT_OICR_CPM_RDY_M | - PFINT_OICR_ECC_ERR_M | + val = (PFINT_OICR_ECC_ERR_M | PFINT_OICR_MAL_DETECT_M | PFINT_OICR_GRST_M | PFINT_OICR_PCI_EXCEPTION_M | - PFINT_OICR_GPIO_M | - PFINT_OICR_STORM_DETECT_M | - PFINT_OICR_HMC_ERR_M); + PFINT_OICR_HMC_ERR_M | + PFINT_OICR_PE_CRITERR_M); wr32(hw, PFINT_OICR_ENA, val); @@ -2058,15 +2071,13 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) skip_req_irq: ice_ena_misc_vector(pf); - val = (pf->oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) | - (ICE_RX_ITR & PFINT_OICR_CTL_ITR_INDX_M) | - PFINT_OICR_CTL_CAUSE_ENA_M; + val = ((pf->oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) | + PFINT_OICR_CTL_CAUSE_ENA_M); wr32(hw, PFINT_OICR_CTL, val); /* This enables Admin queue Interrupt causes */ - val = (pf->oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) | - (ICE_RX_ITR & PFINT_FW_CTL_ITR_INDX_M) | - PFINT_FW_CTL_CAUSE_ENA_M; + val = ((pf->oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) | + PFINT_FW_CTL_CAUSE_ENA_M); wr32(hw, PFINT_FW_CTL, val); itr_gran = hw->itr_gran_200; @@ -3246,8 +3257,10 @@ static void ice_clear_interrupt_scheme(struct ice_pf *pf) if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) ice_dis_msix(pf); - devm_kfree(&pf->pdev->dev, pf->irq_tracker); - pf->irq_tracker = NULL; + if (pf->irq_tracker) { + devm_kfree(&pf->pdev->dev, pf->irq_tracker); + pf->irq_tracker = NULL; + } } /** @@ -3271,7 +3284,7 @@ static int ice_probe(struct pci_dev *pdev, err = pcim_iomap_regions(pdev, BIT(ICE_BAR0), pci_name(pdev)); if (err) { - dev_err(&pdev->dev, "I/O map error %d\n", err); + dev_err(&pdev->dev, "BAR0 I/O map error %d\n", err); return err; } @@ -3720,10 +3733,10 @@ static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) enum ice_status status; /* Here we are configuring the VSI to let the driver add VLAN tags by - * setting port_vlan_flags to ICE_AQ_VSI_PVLAN_MODE_ALL. The actual VLAN - * tag insertion happens in the Tx hot path, in ice_tx_map. + * setting vlan_flags to ICE_AQ_VSI_VLAN_MODE_ALL. The actual VLAN tag + * insertion happens in the Tx hot path, in ice_tx_map. */ - ctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_MODE_ALL; + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); ctxt.vsi_num = vsi->vsi_num; @@ -3735,7 +3748,7 @@ static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) return -EIO; } - vsi->info.port_vlan_flags = ctxt.info.port_vlan_flags; + vsi->info.vlan_flags = ctxt.info.vlan_flags; return 0; } @@ -3757,12 +3770,15 @@ static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) */ if (ena) { /* Strip VLAN tag from Rx packet and put it in the desc */ - ctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_EMOD_STR_BOTH; + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_STR_BOTH; } else { /* Disable stripping. Leave tag in packet */ - ctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_EMOD_NOTHING; + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING; } + /* Allow all packets untagged/tagged */ + ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; + ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); ctxt.vsi_num = vsi->vsi_num; @@ -3773,7 +3789,7 @@ static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) return -EIO; } - vsi->info.port_vlan_flags = ctxt.info.port_vlan_flags; + vsi->info.vlan_flags = ctxt.info.vlan_flags; return 0; } @@ -3986,7 +4002,7 @@ static int ice_setup_rx_ctx(struct ice_ring *ring) /* clear the context structure first */ memset(&rlan_ctx, 0, sizeof(rlan_ctx)); - rlan_ctx.base = ring->dma >> 7; + rlan_ctx.base = ring->dma >> ICE_RLAN_BASE_S; rlan_ctx.qlen = ring->count; @@ -4098,11 +4114,12 @@ static int ice_vsi_cfg(struct ice_vsi *vsi) { int err; - ice_set_rx_mode(vsi->netdev); - - err = ice_restore_vlan(vsi); - if (err) - return err; + if (vsi->netdev) { + ice_set_rx_mode(vsi->netdev); + err = ice_restore_vlan(vsi); + if (err) + return err; + } err = ice_vsi_cfg_txqs(vsi); if (!err) @@ -4868,7 +4885,7 @@ int ice_down(struct ice_vsi *vsi) */ static int ice_vsi_setup_tx_rings(struct ice_vsi *vsi) { - int i, err; + int i, err = 0; if (!vsi->num_txq) { dev_err(&vsi->back->pdev->dev, "VSI %d has 0 Tx queues\n", @@ -4893,7 +4910,7 @@ static int ice_vsi_setup_tx_rings(struct ice_vsi *vsi) */ static int ice_vsi_setup_rx_rings(struct ice_vsi *vsi) { - int i, err; + int i, err = 0; if (!vsi->num_rxq) { dev_err(&vsi->back->pdev->dev, "VSI %d has 0 Rx queues\n", @@ -5235,7 +5252,7 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu) u8 count = 0; if (new_mtu == netdev->mtu) { - netdev_warn(netdev, "mtu is already %d\n", netdev->mtu); + netdev_warn(netdev, "mtu is already %u\n", netdev->mtu); return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c index 92da0a626ce0..295a8cd87fc1 100644 --- a/drivers/net/ethernet/intel/ice/ice_nvm.c +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c @@ -131,9 +131,8 @@ ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data) * * This function will request NVM ownership. */ -static enum -ice_status ice_acquire_nvm(struct ice_hw *hw, - enum ice_aq_res_access_type access) +static enum ice_status +ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access) { if (hw->nvm.blank_nvm_mode) return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 2e6c1d92cc88..eeae199469b6 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -1576,8 +1576,7 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc, return status; } - if (owner == ICE_SCHED_NODE_OWNER_LAN) - vsi->max_lanq[tc] = new_numqs; + vsi->max_lanq[tc] = new_numqs; return status; } diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 723d15f1e90b..6b7ec2ae5ad6 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -645,14 +645,14 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent, act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M; lg_act->pdata.lg_act.act[1] = cpu_to_le32(act); - act = (7 << ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_VALUE_M; + act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX << + ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M; /* Third action Marker value */ act |= ICE_LG_ACT_GENERIC; act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M; - act |= (0 << ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_VALUE_M; lg_act->pdata.lg_act.act[2] = cpu_to_le32(act); /* call the fill switch rule to fill the lookup tx rx structure */ diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 6f4a0d159dbf..9b8ec128ee31 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -17,7 +17,7 @@ struct ice_vsi_ctx { u16 vsis_unallocated; u16 flags; struct ice_aqc_vsi_props info; - bool alloc_from_pool; + u8 alloc_from_pool; }; enum ice_sw_fwd_act_type { @@ -94,8 +94,8 @@ struct ice_fltr_info { u8 qgrp_size; /* Rule creations populate these indicators basing on the switch type */ - bool lb_en; /* Indicate if packet can be looped back */ - bool lan_en; /* Indicate if packet can be forwarded to the uplink */ + u8 lb_en; /* Indicate if packet can be looped back */ + u8 lan_en; /* Indicate if packet can be forwarded to the uplink */ }; /* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list id */ diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 567067b650c4..31bc998fe200 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -143,7 +143,7 @@ struct ice_ring { u16 next_to_use; u16 next_to_clean; - bool ring_active; /* is ring online or not */ + u8 ring_active; /* is ring online or not */ /* stats structs */ struct ice_q_stats stats; diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 99c8a9a71b5e..97c366e0ca59 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -83,7 +83,7 @@ struct ice_link_status { u64 phy_type_low; u16 max_frame_size; u16 link_speed; - bool lse_ena; /* Link Status Event notification */ + u8 lse_ena; /* Link Status Event notification */ u8 link_info; u8 an_info; u8 ext_info; @@ -101,7 +101,7 @@ struct ice_phy_info { struct ice_link_status link_info_old; u64 phy_type_low; enum ice_media_type media_type; - bool get_link_info; + u8 get_link_info; }; /* Common HW capabilities for SW use */ @@ -167,7 +167,7 @@ struct ice_nvm_info { u32 oem_ver; /* OEM version info */ u16 sr_words; /* Shadow RAM size in words */ u16 ver; /* NVM package version */ - bool blank_nvm_mode; /* is NVM empty (no FW present) */ + u8 blank_nvm_mode; /* is NVM empty (no FW present) */ }; /* Max number of port to queue branches w.r.t topology */ @@ -181,7 +181,7 @@ struct ice_sched_node { struct ice_aqc_txsched_elem_data info; u32 agg_id; /* aggregator group id */ u16 vsi_id; - bool in_use; /* suspended or in use */ + u8 in_use; /* suspended or in use */ u8 tx_sched_layer; /* Logical Layer (1-9) */ u8 num_children; u8 tc_num; @@ -218,7 +218,7 @@ struct ice_sched_vsi_info { struct ice_sched_tx_policy { u16 max_num_vsis; u8 max_num_lan_qs_per_tc[ICE_MAX_TRAFFIC_CLASS]; - bool rdma_ena; + u8 rdma_ena; }; struct ice_port_info { @@ -243,7 +243,7 @@ struct ice_port_info { struct list_head agg_list; /* lists all aggregator */ u8 lport; #define ICE_LPORT_MASK 0xff - bool is_vf; + u8 is_vf; }; struct ice_switch_info { @@ -287,7 +287,7 @@ struct ice_hw { u8 max_cgds; u8 sw_entry_point_layer; - bool evb_veb; /* true for VEB, false for VEPA */ + u8 evb_veb; /* true for VEB, false for VEPA */ struct ice_bus_info bus; struct ice_nvm_info nvm; struct ice_hw_dev_caps dev_caps; /* device capabilities */ @@ -318,7 +318,7 @@ struct ice_hw { u8 itr_gran_100; u8 itr_gran_50; u8 itr_gran_25; - bool ucast_shared; /* true if VSIs can share unicast addr */ + u8 ucast_shared; /* true if VSIs can share unicast addr */ }; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index f92f7918112d..5acf3b743876 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -1649,7 +1649,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) if (hw->phy.type == e1000_phy_m88) igb_phy_disable_receiver(adapter); - mdelay(500); + msleep(500); return 0; } diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index d03c2f0d7592..a32c576c1e65 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3873,7 +3873,7 @@ static int igb_sw_init(struct igb_adapter *adapter) adapter->mac_table = kcalloc(hw->mac.rar_entry_count, sizeof(struct igb_mac_addr), - GFP_ATOMIC); + GFP_KERNEL); if (!adapter->mac_table) return -ENOMEM; @@ -3883,7 +3883,7 @@ static int igb_sw_init(struct igb_adapter *adapter) /* Setup and initialize a copy of the hw vlan table array */ adapter->shadow_vfta = kcalloc(E1000_VLAN_FILTER_TBL_SIZE, sizeof(u32), - GFP_ATOMIC); + GFP_KERNEL); if (!adapter->shadow_vfta) return -ENOMEM; @@ -5816,7 +5816,8 @@ static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first) if (skb->ip_summed != CHECKSUM_PARTIAL) { csum_failed: - if (!(first->tx_flags & IGB_TX_FLAGS_VLAN)) + if (!(first->tx_flags & IGB_TX_FLAGS_VLAN) && + !tx_ring->launchtime_enable) return; goto no_csum; } diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index 43664adf7a3c..d3e72d0f66ef 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -771,14 +771,13 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter) rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc); rxdr->size = ALIGN(rxdr->size, 4096); - rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, - GFP_KERNEL); + rxdr->desc = dma_zalloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, + GFP_KERNEL); if (!rxdr->desc) { vfree(rxdr->buffer_info); return -ENOMEM; } - memset(rxdr->desc, 0, rxdr->size); rxdr->next_to_clean = 0; rxdr->next_to_use = 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c index 94b3165ff543..ccd852ad62a4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c @@ -192,7 +192,7 @@ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid, } /* alloc the udl from per cpu ddp pool */ - ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp); + ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_KERNEL, &ddp->udp); if (!ddp->udl) { e_err(drv, "failed allocated ddp context\n"); goto out_noddp_unmap; @@ -760,7 +760,7 @@ int ixgbe_setup_fcoe_ddp_resources(struct ixgbe_adapter *adapter) return 0; /* Extra buffer to be shared by all DDPs for HW work around */ - buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC); + buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_KERNEL); if (!buffer) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 447098005490..9a23d33a47ed 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6201,7 +6201,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter, adapter->mac_table = kcalloc(hw->mac.num_rar_entries, sizeof(struct ixgbe_mac_addr), - GFP_ATOMIC); + GFP_KERNEL); if (!adapter->mac_table) return -ENOMEM; @@ -6620,8 +6620,18 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) struct ixgbe_adapter *adapter = netdev_priv(netdev); if (adapter->xdp_prog) { - e_warn(probe, "MTU cannot be changed while XDP program is loaded\n"); - return -EPERM; + int new_frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + + VLAN_HLEN; + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbe_ring *ring = adapter->rx_ring[i]; + + if (new_frame_size > ixgbe_rx_bufsz(ring)) { + e_warn(probe, "Requested MTU size is not supported with XDP\n"); + return -EINVAL; + } + } } /* @@ -8983,6 +8993,15 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc) #ifdef CONFIG_IXGBE_DCB if (tc) { + if (adapter->xdp_prog) { + e_warn(probe, "DCB is not supported with XDP\n"); + + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(dev)) + ixgbe_open(dev); + return -EINVAL; + } + netdev_set_num_tc(dev, tc); ixgbe_set_prio_tc_map(adapter); @@ -9171,14 +9190,12 @@ static int parse_tc_actions(struct ixgbe_adapter *adapter, struct tcf_exts *exts, u64 *action, u8 *queue) { const struct tc_action *a; - LIST_HEAD(actions); + int i; if (!tcf_exts_has_actions(exts)) return -EINVAL; - tcf_exts_to_list(exts, &actions); - list_for_each_entry(a, &actions, list) { - + tcf_exts_for_each_action(i, a, exts) { /* Drop action */ if (is_tcf_gact_shot(a)) { *action = IXGBE_FDIR_DROP_QUEUE; @@ -9936,6 +9953,11 @@ static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev) int tcs = adapter->hw_tcs ? : 1; int pool, err; + if (adapter->xdp_prog) { + e_warn(probe, "L2FW offload is not supported with XDP\n"); + return ERR_PTR(-EINVAL); + } + /* The hardware supported by ixgbe only filters on the destination MAC * address. In order to avoid issues we only support offloading modes * where the hardware can actually provide the functionality. diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 6f59933cdff7..3c6f01c41b78 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -53,6 +53,11 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter, struct ixgbe_hw *hw = &adapter->hw; int i; + if (adapter->xdp_prog) { + e_warn(probe, "SRIOV is not supported with XDP\n"); + return -EINVAL; + } + /* Enable VMDq flag so device will be set in VM mode */ adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED | IXGBE_FLAG_VMDQ_ENABLED; @@ -688,8 +693,13 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) { struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ]; struct vf_data_storage *vfinfo = &adapter->vfinfo[vf]; + u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask); u8 num_tcs = adapter->hw_tcs; + u32 reg_val; + u32 queue; + u32 word; /* remove VLAN filters beloning to this VF */ ixgbe_clear_vf_vlans(adapter, vf); @@ -726,6 +736,27 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) /* reset VF api back to unknown */ adapter->vfinfo[vf].vf_api = ixgbe_mbox_api_10; + + /* Restart each queue for given VF */ + for (queue = 0; queue < q_per_pool; queue++) { + unsigned int reg_idx = (vf * q_per_pool) + queue; + + reg_val = IXGBE_READ_REG(hw, IXGBE_PVFTXDCTL(reg_idx)); + + /* Re-enabling only configured queues */ + if (reg_val) { + reg_val |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_PVFTXDCTL(reg_idx), reg_val); + reg_val &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_PVFTXDCTL(reg_idx), reg_val); + } + } + + /* Clear VF's mailbox memory */ + for (word = 0; word < IXGBE_VFMAILBOX_SIZE; word++) + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf), word, 0); + + IXGBE_WRITE_FLUSH(hw); } static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 44cfb2021145..41bcbb337e83 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -2518,6 +2518,7 @@ enum { /* Translated register #defines */ #define IXGBE_PVFTDH(P) (0x06010 + (0x40 * (P))) #define IXGBE_PVFTDT(P) (0x06018 + (0x40 * (P))) +#define IXGBE_PVFTXDCTL(P) (0x06028 + (0x40 * (P))) #define IXGBE_PVFTDWBAL(P) (0x06038 + (0x40 * (P))) #define IXGBE_PVFTDWBAH(P) (0x0603C + (0x40 * (P))) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9131a1376e7d..9fed54017659 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1982,14 +1982,15 @@ static bool modify_header_match_supported(struct mlx5_flow_spec *spec, goto out_ok; modify_ip_header = false; - tcf_exts_to_list(exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, exts) { + int k; + if (!is_tcf_pedit(a)) continue; nkeys = tcf_pedit_nkeys(a); - for (i = 0; i < nkeys; i++) { - htype = tcf_pedit_htype(a, i); + for (k = 0; k < nkeys; k++) { + htype = tcf_pedit_htype(a, k); if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6) { modify_ip_header = true; @@ -2053,15 +2054,14 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, const struct tc_action *a; LIST_HEAD(actions); u32 action = 0; - int err; + int err, i; if (!tcf_exts_has_actions(exts)) return -EINVAL; attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; - tcf_exts_to_list(exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, exts) { if (is_tcf_gact_shot(a)) { action |= MLX5_FLOW_CONTEXT_ACTION_DROP; if (MLX5_CAP_FLOWTABLE(priv->mdev, @@ -2666,7 +2666,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, LIST_HEAD(actions); bool encap = false; u32 action = 0; - int err; + int err, i; if (!tcf_exts_has_actions(exts)) return -EINVAL; @@ -2674,8 +2674,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, attr->in_rep = rpriv->rep; attr->in_mdev = priv->mdev; - tcf_exts_to_list(exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, exts) { if (is_tcf_gact_shot(a)) { action |= MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 6070d1591d1e..930700413b1d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1346,8 +1346,7 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port, return -ENOMEM; mall_tc_entry->cookie = f->cookie; - tcf_exts_to_list(f->exts, &actions); - a = list_first_entry(&actions, struct tc_action, list); + a = tcf_exts_first_action(f->exts); if (is_tcf_mirred_egress_mirror(a) && protocol == htons(ETH_P_ALL)) { struct mlxsw_sp_port_mall_mirror_tc_entry *mirror; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 3ae930196741..3cdb7aca90b7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -414,6 +414,8 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); +void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev); /* spectrum_kvdl.c */ enum mlxsw_sp_kvdl_entry_type { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index ebd1b24ebaa5..8d211972c5e9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -21,8 +21,7 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, struct netlink_ext_ack *extack) { const struct tc_action *a; - LIST_HEAD(actions); - int err; + int err, i; if (!tcf_exts_has_actions(exts)) return 0; @@ -32,8 +31,7 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, if (err) return err; - tcf_exts_to_list(exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, exts) { if (is_tcf_gact_ok(a)) { err = mlxsw_sp_acl_rulei_act_terminate(rulei); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 3a96307f51b0..2ab9cf25a08a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -6234,6 +6234,17 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) mlxsw_sp_vr_put(mlxsw_sp, vr); } +void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev) +{ + struct mlxsw_sp_rif *rif; + + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); + if (!rif) + return; + mlxsw_sp_rif_destroy(rif); +} + static void mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params, struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0d8444aaba01..db715da7bab7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -127,6 +127,24 @@ bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp, return !!mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); } +static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev, + void *data) +{ + struct mlxsw_sp *mlxsw_sp = data; + + mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev); + return 0; +} + +static void mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev) +{ + mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev); + netdev_walk_all_upper_dev_rcu(dev, + mlxsw_sp_bridge_device_upper_rif_destroy, + mlxsw_sp); +} + static struct mlxsw_sp_bridge_device * mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, struct net_device *br_dev) @@ -165,6 +183,8 @@ static void mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, struct mlxsw_sp_bridge_device *bridge_device) { + mlxsw_sp_bridge_device_rifs_destroy(bridge->mlxsw_sp, + bridge_device->dev); list_del(&bridge_device->list); if (bridge_device->vlan_enabled) bridge->vlan_enabled_exists = false; diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c index 0ba0356ec4e6..9044496803e6 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/action.c +++ b/drivers/net/ethernet/netronome/nfp/flower/action.c @@ -796,11 +796,10 @@ int nfp_flower_compile_action(struct nfp_app *app, struct net_device *netdev, struct nfp_fl_payload *nfp_flow) { - int act_len, act_cnt, err, tun_out_cnt, out_cnt; + int act_len, act_cnt, err, tun_out_cnt, out_cnt, i; enum nfp_flower_tun_type tun_type; const struct tc_action *a; u32 csum_updated = 0; - LIST_HEAD(actions); memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ); nfp_flow->meta.act_len = 0; @@ -810,8 +809,7 @@ int nfp_flower_compile_action(struct nfp_app *app, tun_out_cnt = 0; out_cnt = 0; - tcf_exts_to_list(flow->exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, flow->exts) { err = nfp_flower_loop_action(app, a, flow, nfp_flow, &act_len, netdev, &tun_type, &tun_out_cnt, &out_cnt, &csum_updated); diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c index d9ab5add27a8..34193c2f1699 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -407,7 +407,7 @@ static void qed_init_cmd_rd(struct qed_hwfn *p_hwfn, if (i == QED_INIT_MAX_POLL_COUNT) { DP_ERR(p_hwfn, - "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparsion %08x)]\n", + "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparison %08x)]\n", addr, le32_to_cpu(cmd->expected_val), val, le32_to_cpu(cmd->op_data)); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index d89a0e22f6e4..5d37ec7e9b0b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -48,7 +48,7 @@ #include "qed_reg_addr.h" #include "qed_sriov.h" -#define CHIP_MCP_RESP_ITER_US 10 +#define QED_MCP_RESP_ITER_US 10 #define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ #define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ @@ -183,18 +183,57 @@ int qed_mcp_free(struct qed_hwfn *p_hwfn) return 0; } +/* Maximum of 1 sec to wait for the SHMEM ready indication */ +#define QED_MCP_SHMEM_RDY_MAX_RETRIES 20 +#define QED_MCP_SHMEM_RDY_ITER_MS 50 + static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_mcp_info *p_info = p_hwfn->mcp_info; + u8 cnt = QED_MCP_SHMEM_RDY_MAX_RETRIES; + u8 msec = QED_MCP_SHMEM_RDY_ITER_MS; u32 drv_mb_offsize, mfw_mb_offsize; u32 mcp_pf_id = MCP_PF_ID(p_hwfn); p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); - if (!p_info->public_base) - return 0; + if (!p_info->public_base) { + DP_NOTICE(p_hwfn, + "The address of the MCP scratch-pad is not configured\n"); + return -EINVAL; + } p_info->public_base |= GRCBASE_MCP; + /* Get the MFW MB address and number of supported messages */ + mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, + SECTION_OFFSIZE_ADDR(p_info->public_base, + PUBLIC_MFW_MB)); + p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); + p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, + p_info->mfw_mb_addr + + offsetof(struct public_mfw_mb, + sup_msgs)); + + /* The driver can notify that there was an MCP reset, and might read the + * SHMEM values before the MFW has completed initializing them. + * To avoid this, the "sup_msgs" field in the MFW mailbox is used as a + * data ready indication. + */ + while (!p_info->mfw_mb_length && --cnt) { + msleep(msec); + p_info->mfw_mb_length = + (u16)qed_rd(p_hwfn, p_ptt, + p_info->mfw_mb_addr + + offsetof(struct public_mfw_mb, sup_msgs)); + } + + if (!cnt) { + DP_NOTICE(p_hwfn, + "Failed to get the SHMEM ready notification after %d msec\n", + QED_MCP_SHMEM_RDY_MAX_RETRIES * msec); + return -EBUSY; + } + /* Calculate the driver and MFW mailbox address */ drv_mb_offsize = qed_rd(p_hwfn, p_ptt, SECTION_OFFSIZE_ADDR(p_info->public_base, @@ -204,13 +243,6 @@ static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); - /* Set the MFW MB address */ - mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, - SECTION_OFFSIZE_ADDR(p_info->public_base, - PUBLIC_MFW_MB)); - p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); - p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, p_info->mfw_mb_addr); - /* Get the current driver mailbox sequence before sending * the first command */ @@ -285,9 +317,15 @@ static void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 org_mcp_reset_seq, seq, delay = CHIP_MCP_RESP_ITER_US, cnt = 0; + u32 org_mcp_reset_seq, seq, delay = QED_MCP_RESP_ITER_US, cnt = 0; int rc = 0; + if (p_hwfn->mcp_info->b_block_cmd) { + DP_NOTICE(p_hwfn, + "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); + return -EBUSY; + } + /* Ensure that only a single thread is accessing the mailbox */ spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); @@ -413,14 +451,41 @@ static void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, (p_mb_params->cmd | seq_num), p_mb_params->param); } +static void qed_mcp_cmd_set_blocking(struct qed_hwfn *p_hwfn, bool block_cmd) +{ + p_hwfn->mcp_info->b_block_cmd = block_cmd; + + DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", + block_cmd ? "Block" : "Unblock"); +} + +static void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; + u32 delay = QED_MCP_RESP_ITER_US; + + cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); + cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); + cpu_pc_0 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); + udelay(delay); + cpu_pc_1 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); + udelay(delay); + cpu_pc_2 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); + + DP_NOTICE(p_hwfn, + "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", + cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); +} + static int _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_mcp_mb_params *p_mb_params, - u32 max_retries, u32 delay) + u32 max_retries, u32 usecs) { + u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); struct qed_mcp_cmd_elem *p_cmd_elem; - u32 cnt = 0; u16 seq_num; int rc = 0; @@ -443,7 +508,11 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, goto err; spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); - udelay(delay); + + if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) + msleep(msecs); + else + udelay(usecs); } while (++cnt < max_retries); if (cnt >= max_retries) { @@ -472,7 +541,11 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, * The spinlock stays locked until the list element is removed. */ - udelay(delay); + if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) + msleep(msecs); + else + udelay(usecs); + spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); if (p_cmd_elem->b_is_completed) @@ -491,11 +564,15 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, DP_NOTICE(p_hwfn, "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", p_mb_params->cmd, p_mb_params->param); + qed_mcp_print_cpu_info(p_hwfn, p_ptt); spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); + if (!QED_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) + qed_mcp_cmd_set_blocking(p_hwfn, true); + return -EAGAIN; } @@ -507,7 +584,7 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", p_mb_params->mcp_resp, p_mb_params->mcp_param, - (cnt * delay) / 1000, (cnt * delay) % 1000); + (cnt * usecs) / 1000, (cnt * usecs) % 1000); /* Clear the sequence number from the MFW response */ p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; @@ -525,7 +602,7 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, { size_t union_data_size = sizeof(union drv_union_data); u32 max_retries = QED_DRV_MB_MAX_RETRIES; - u32 delay = CHIP_MCP_RESP_ITER_US; + u32 usecs = QED_MCP_RESP_ITER_US; /* MCP not initialized */ if (!qed_mcp_is_init(p_hwfn)) { @@ -533,6 +610,13 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, return -EBUSY; } + if (p_hwfn->mcp_info->b_block_cmd) { + DP_NOTICE(p_hwfn, + "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", + p_mb_params->cmd, p_mb_params->param); + return -EBUSY; + } + if (p_mb_params->data_src_size > union_data_size || p_mb_params->data_dst_size > union_data_size) { DP_ERR(p_hwfn, @@ -542,8 +626,13 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, return -EINVAL; } + if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { + max_retries = DIV_ROUND_UP(max_retries, 1000); + usecs *= 1000; + } + return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, - delay); + usecs); } int qed_mcp_cmd(struct qed_hwfn *p_hwfn, @@ -761,6 +850,7 @@ __qed_mcp_load_req(struct qed_hwfn *p_hwfn, mb_params.data_src_size = sizeof(load_req); mb_params.p_data_dst = &load_rsp; mb_params.data_dst_size = sizeof(load_rsp); + mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; DP_VERBOSE(p_hwfn, QED_MSG_SP, "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", @@ -982,7 +1072,8 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn, int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 wol_param, mcp_resp, mcp_param; + struct qed_mcp_mb_params mb_params; + u32 wol_param; switch (p_hwfn->cdev->wol_config) { case QED_OV_WOL_DISABLED: @@ -1000,8 +1091,12 @@ int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; } - return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_UNLOAD_REQ, wol_param, - &mcp_resp, &mcp_param); + memset(&mb_params, 0, sizeof(mb_params)); + mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; + mb_params.param = wol_param; + mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; + + return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); } int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) @@ -2077,31 +2172,65 @@ qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, return rc; } +/* A maximal 100 msec waiting time for the MCP to halt */ +#define QED_MCP_HALT_SLEEP_MS 10 +#define QED_MCP_HALT_MAX_RETRIES 10 + int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 resp = 0, param = 0; + u32 resp = 0, param = 0, cpu_state, cnt = 0; int rc; rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, ¶m); - if (rc) + if (rc) { DP_ERR(p_hwfn, "MCP response failure, aborting\n"); + return rc; + } - return rc; + do { + msleep(QED_MCP_HALT_SLEEP_MS); + cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); + if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) + break; + } while (++cnt < QED_MCP_HALT_MAX_RETRIES); + + if (cnt == QED_MCP_HALT_MAX_RETRIES) { + DP_NOTICE(p_hwfn, + "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", + qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); + return -EBUSY; + } + + qed_mcp_cmd_set_blocking(p_hwfn, true); + + return 0; } +#define QED_MCP_RESUME_SLEEP_MS 10 + int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 value, cpu_mode; + u32 cpu_mode, cpu_state; qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); - value = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); - value &= ~MCP_REG_CPU_MODE_SOFT_HALT; - qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, value); cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); + cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; + qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); + msleep(QED_MCP_RESUME_SLEEP_MS); + cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); - return (cpu_mode & MCP_REG_CPU_MODE_SOFT_HALT) ? -EAGAIN : 0; + if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { + DP_NOTICE(p_hwfn, + "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", + cpu_mode, cpu_state); + return -EBUSY; + } + + qed_mcp_cmd_set_blocking(p_hwfn, false); + + return 0; } int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 047976d5c6e9..85e6b3989e7a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -635,11 +635,14 @@ struct qed_mcp_info { */ spinlock_t cmd_lock; + /* Flag to indicate whether sending a MFW mailbox command is blocked */ + bool b_block_cmd; + /* Spinlock used for syncing SW link-changes and link-changes * originating from attention context. */ spinlock_t link_lock; - bool block_mb_sending; + u32 public_base; u32 drv_mb_addr; u32 mfw_mb_addr; @@ -660,14 +663,20 @@ struct qed_mcp_info { }; struct qed_mcp_mb_params { - u32 cmd; - u32 param; - void *p_data_src; - u8 data_src_size; - void *p_data_dst; - u8 data_dst_size; - u32 mcp_resp; - u32 mcp_param; + u32 cmd; + u32 param; + void *p_data_src; + void *p_data_dst; + u8 data_src_size; + u8 data_dst_size; + u32 mcp_resp; + u32 mcp_param; + u32 flags; +#define QED_MB_FLAG_CAN_SLEEP (0x1 << 0) +#define QED_MB_FLAG_AVOID_BLOCK (0x1 << 1) +#define QED_MB_FLAGS_IS_SET(params, flag) \ + ({ typeof(params) __params = (params); \ + (__params && (__params->flags & QED_MB_FLAG_ ## flag)); }) }; struct qed_drv_tlv_hdr { diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index d8ad2dcad8d5..f736f70956fd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -562,8 +562,10 @@ 0 #define MCP_REG_CPU_STATE \ 0xe05004UL +#define MCP_REG_CPU_STATE_SOFT_HALTED (0x1UL << 10) #define MCP_REG_CPU_EVENT_MASK \ 0xe05008UL +#define MCP_REG_CPU_PROGRAM_COUNTER 0xe0501cUL #define PGLUE_B_REG_PF_BAR0_SIZE \ 0x2aae60UL #define PGLUE_B_REG_PF_BAR1_SIZE \ diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c index 9673d19308e6..b16ce7d93caf 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c @@ -2006,18 +2006,16 @@ unlock: static int qede_parse_actions(struct qede_dev *edev, struct tcf_exts *exts) { - int rc = -EINVAL, num_act = 0; + int rc = -EINVAL, num_act = 0, i; const struct tc_action *a; bool is_drop = false; - LIST_HEAD(actions); if (!tcf_exts_has_actions(exts)) { DP_NOTICE(edev, "No tc actions received\n"); return rc; } - tcf_exts_to_list(exts, &actions); - list_for_each_entry(a, &actions, list) { + tcf_exts_for_each_action(i, a, exts) { num_act++; if (is_tcf_gact_shot(a)) diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 353f1c129af1..059ba9429e51 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2384,26 +2384,20 @@ static int qlge_update_hw_vlan_features(struct net_device *ndev, return status; } -static netdev_features_t qlge_fix_features(struct net_device *ndev, - netdev_features_t features) -{ - int err; - - /* Update the behavior of vlan accel in the adapter */ - err = qlge_update_hw_vlan_features(ndev, features); - if (err) - return err; - - return features; -} - static int qlge_set_features(struct net_device *ndev, netdev_features_t features) { netdev_features_t changed = ndev->features ^ features; + int err; + + if (changed & NETIF_F_HW_VLAN_CTAG_RX) { + /* Update the behavior of vlan accel in the adapter */ + err = qlge_update_hw_vlan_features(ndev, features); + if (err) + return err; - if (changed & NETIF_F_HW_VLAN_CTAG_RX) qlge_vlan_mode(ndev, features); + } return 0; } @@ -4719,7 +4713,6 @@ static const struct net_device_ops qlge_netdev_ops = { .ndo_set_mac_address = qlge_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = qlge_tx_timeout, - .ndo_fix_features = qlge_fix_features, .ndo_set_features = qlge_set_features, .ndo_vlan_rx_add_vid = qlge_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qlge_vlan_rx_kill_vid, diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index b81f4faf7b10..1470fc12282b 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* Renesas Ethernet AVB device driver * * Copyright (C) 2014-2015 Renesas Electronics Corporation @@ -5,10 +6,6 @@ * Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com> * * Based on the SuperH Ethernet driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #ifndef __RAVB_H__ diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index c06f2df895c2..aff5516b781e 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* Renesas Ethernet AVB device driver * * Copyright (C) 2014-2015 Renesas Electronics Corporation @@ -5,10 +6,6 @@ * Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com> * * Based on the SuperH Ethernet driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/cache.h> diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 5573199c4536..ad4433d59237 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* SuperH Ethernet device driver * * Copyright (C) 2014 Renesas Electronics Corporation @@ -5,18 +6,6 @@ * Copyright (C) 2008-2014 Renesas Solutions Corp. * Copyright (C) 2013-2017 Cogent Embedded, Inc. * Copyright (C) 2014 Codethink Limited - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". */ #include <linux/module.h> diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index f94be99cf400..0c18650bbfe6 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* SuperH Ethernet device driver * * Copyright (C) 2006-2012 Nobuhiro Iwamatsu * Copyright (C) 2008-2012 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". */ #ifndef __SH_ETH_H__ diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 05157442a980..b1b53f6c452f 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -74,7 +74,6 @@ static const char version[] = #include <linux/skbuff.h> #include <linux/dmaengine.h> -#include <linux/dma/pxa-dma.h> #include <asm/io.h> @@ -1795,7 +1794,6 @@ static int smc911x_probe(struct net_device *dev) #ifdef SMC_USE_DMA struct dma_slave_config config; dma_cap_mask_t mask; - struct pxad_param param; #endif DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); @@ -1971,15 +1969,8 @@ static int smc911x_probe(struct net_device *dev) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - param.prio = PXAD_PRIO_LOWEST; - param.drcmr = -1UL; - - lp->rxdma = - dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, "rx"); - lp->txdma = - dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, "tx"); + lp->rxdma = dma_request_channel(mask, NULL, NULL); + lp->txdma = dma_request_channel(mask, NULL, NULL); lp->rxdma_active = 0; lp->txdma_active = 0; diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 080428762858..b944828f9ea3 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2019,17 +2019,10 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr, # endif if (lp->cfg.flags & SMC91X_USE_DMA) { dma_cap_mask_t mask; - struct pxad_param param; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - param.prio = PXAD_PRIO_LOWEST; - param.drcmr = -1UL; - - lp->dma_chan = - dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, - "data"); + lp->dma_chan = dma_request_channel(mask, NULL, NULL); } #endif diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h index b337ee97e0c0..a27352229fc2 100644 --- a/drivers/net/ethernet/smsc/smc91x.h +++ b/drivers/net/ethernet/smsc/smc91x.h @@ -301,7 +301,6 @@ struct smc_local { * as RX which can overrun memory and lose packets. */ #include <linux/dma-mapping.h> -#include <linux/dma/pxa-dma.h> #ifdef SMC_insl #undef SMC_insl diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index edf20361ea5f..bf4acebb6bcd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -33,7 +33,7 @@ config DWMAC_DWC_QOS_ETH select PHYLIB select CRC32 select MII - depends on OF && COMMON_CLK && HAS_DMA + depends on OF && HAS_DMA help Support for chips using the snps,dwc-qos-ethernet.txt DT binding. @@ -57,7 +57,7 @@ config DWMAC_ANARION config DWMAC_IPQ806X tristate "QCA IPQ806x DWMAC support" default ARCH_QCOM - depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST) + depends on OF && (ARCH_QCOM || COMPILE_TEST) select MFD_SYSCON help Support for QCA IPQ806X DWMAC Ethernet. @@ -100,7 +100,7 @@ config DWMAC_OXNAS config DWMAC_ROCKCHIP tristate "Rockchip dwmac support" default ARCH_ROCKCHIP - depends on OF && COMMON_CLK && (ARCH_ROCKCHIP || COMPILE_TEST) + depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) select MFD_SYSCON help Support for Ethernet controller on Rockchip RK3288 SoC. @@ -123,7 +123,7 @@ config DWMAC_SOCFPGA config DWMAC_STI tristate "STi GMAC support" default ARCH_STI - depends on OF && COMMON_CLK && (ARCH_STI || COMPILE_TEST) + depends on OF && (ARCH_STI || COMPILE_TEST) select MFD_SYSCON ---help--- Support for ethernet controller on STi SOCs. @@ -147,7 +147,7 @@ config DWMAC_STM32 config DWMAC_SUNXI tristate "Allwinner GMAC support" default ARCH_SUNXI - depends on OF && COMMON_CLK && (ARCH_SUNXI || COMPILE_TEST) + depends on OF && (ARCH_SUNXI || COMPILE_TEST) ---help--- Support for Allwinner A20/A31 GMAC ethernet controllers. diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 1a96dd9c1091..531294f4978b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -61,7 +61,7 @@ static int tc_fill_actions(struct stmmac_tc_entry *entry, struct stmmac_tc_entry *action_entry = entry; const struct tc_action *act; struct tcf_exts *exts; - LIST_HEAD(actions); + int i; exts = cls->knode.exts; if (!tcf_exts_has_actions(exts)) @@ -69,8 +69,7 @@ static int tc_fill_actions(struct stmmac_tc_entry *entry, if (frag) action_entry = frag; - tcf_exts_to_list(exts, &actions); - list_for_each_entry(act, &actions, list) { + tcf_exts_for_each_action(i, act, exts) { /* Accept */ if (is_tcf_gact_ok(act)) { action_entry->val.af = 1; diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 507f68190cb1..1121a1ec407c 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -29,6 +29,7 @@ #include <linux/netdevice.h> #include <linux/inetdevice.h> #include <linux/etherdevice.h> +#include <linux/pci.h> #include <linux/skbuff.h> #include <linux/if_vlan.h> #include <linux/in.h> @@ -2039,12 +2040,16 @@ static int netvsc_register_vf(struct net_device *vf_netdev) { struct net_device *ndev; struct net_device_context *net_device_ctx; + struct device *pdev = vf_netdev->dev.parent; struct netvsc_device *netvsc_dev; int ret; if (vf_netdev->addr_len != ETH_ALEN) return NOTIFY_DONE; + if (!pdev || !dev_is_pci(pdev) || dev_is_pf(pdev)) + return NOTIFY_DONE; + /* * We will use the MAC address to locate the synthetic interface to * associate with the VF interface. If we don't find a matching diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 2bbefe828670..ebd07ad82431 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -3217,7 +3217,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on) goto out; if (on) { - __f_setown(file, task_pid(current), PIDTYPE_PID, 0); + __f_setown(file, task_pid(current), PIDTYPE_TGID, 0); tfile->flags |= TUN_FASYNC; } else tfile->flags &= ~TUN_FASYNC; diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 97742708460b..2cd71bdb6484 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -5217,8 +5217,8 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->hw_features &= ~NETIF_F_RXCSUM; } - if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && - udev->serial && !strcmp(udev->serial, "000001000000")) { + if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial && + (!strcmp(udev->serial, "000001000000") || !strcmp(udev->serial, "000002000000"))) { dev_info(&udev->dev, "Dell TB16 Dock, disable RX aggregation"); set_bit(DELL_TB_RX_AGG_BUG, &tp->flags); } diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 27902a8799b1..8aae6dcc839f 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -812,9 +812,9 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd, * overshoots the remainder by 4 bytes, assume it was * including 'status'. */ - if (out_field[1] - 8 == remainder) + if (out_field[1] - 4 == remainder) return remainder; - return out_field[1] - 4; + return out_field[1] - 8; } else if (cmd == ND_CMD_CALL) { struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field; diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 233907889f96..6c8fb7590838 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -34,6 +34,9 @@ static int nvdimm_probe(struct device *dev) return rc; } + /* reset locked, to be validated below... */ + nvdimm_clear_locked(dev); + ndd = kzalloc(sizeof(*ndd), GFP_KERNEL); if (!ndd) return -ENOMEM; @@ -48,12 +51,30 @@ static int nvdimm_probe(struct device *dev) get_device(dev); kref_init(&ndd->kref); + /* + * EACCES failures reading the namespace label-area-properties + * are interpreted as the DIMM capacity being locked but the + * namespace labels themselves being accessible. + */ rc = nvdimm_init_nsarea(ndd); - if (rc == -EACCES) + if (rc == -EACCES) { + /* + * See nvdimm_namespace_common_probe() where we fail to + * allow namespaces to probe while the DIMM is locked, + * but we do allow for namespace enumeration. + */ nvdimm_set_locked(dev); + rc = 0; + } if (rc) goto err; + /* + * EACCES failures reading the namespace label-data are + * interpreted as the label area being locked in addition to the + * DIMM capacity. We fail the dimm probe to prevent regions from + * attempting to parse the label area. + */ rc = nvdimm_init_config_data(ndd); if (rc == -EACCES) nvdimm_set_locked(dev); @@ -72,7 +93,6 @@ static int nvdimm_probe(struct device *dev) if (rc == 0) nvdimm_set_aliasing(dev); } - nvdimm_clear_locked(dev); nvdimm_bus_unlock(dev); if (rc) diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 8d348b22ba45..863cabc35215 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -537,6 +537,37 @@ resource_size_t nd_blk_available_dpa(struct nd_region *nd_region) } /** + * nd_pmem_max_contiguous_dpa - For the given dimm+region, return the max + * contiguous unallocated dpa range. + * @nd_region: constrain available space check to this reference region + * @nd_mapping: container of dpa-resource-root + labels + */ +resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region, + struct nd_mapping *nd_mapping) +{ + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); + struct nvdimm_bus *nvdimm_bus; + resource_size_t max = 0; + struct resource *res; + + /* if a dimm is disabled the available capacity is zero */ + if (!ndd) + return 0; + + nvdimm_bus = walk_to_nvdimm_bus(ndd->dev); + if (__reserve_free_pmem(&nd_region->dev, nd_mapping->nvdimm)) + return 0; + for_each_dpa_resource(ndd, res) { + if (strcmp(res->name, "pmem-reserve") != 0) + continue; + if (resource_size(res) > max) + max = resource_size(res); + } + release_free_pmem(nvdimm_bus, nd_mapping); + return max; +} + +/** * nd_pmem_available_dpa - for the given dimm+region account unallocated dpa * @nd_mapping: container of dpa-resource-root + labels * @nd_region: constrain available space check to this reference region diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 28afdd668905..4a4266250c28 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -799,7 +799,7 @@ static int merge_dpa(struct nd_region *nd_region, return 0; } -static int __reserve_free_pmem(struct device *dev, void *data) +int __reserve_free_pmem(struct device *dev, void *data) { struct nvdimm *nvdimm = data; struct nd_region *nd_region; @@ -836,7 +836,7 @@ static int __reserve_free_pmem(struct device *dev, void *data) return 0; } -static void release_free_pmem(struct nvdimm_bus *nvdimm_bus, +void release_free_pmem(struct nvdimm_bus *nvdimm_bus, struct nd_mapping *nd_mapping) { struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); @@ -1032,7 +1032,7 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) allocated += nvdimm_allocated_dpa(ndd, &label_id); } - available = nd_region_available_dpa(nd_region); + available = nd_region_allocatable_dpa(nd_region); if (val > available + allocated) return -ENOSPC; @@ -1144,6 +1144,26 @@ resource_size_t nvdimm_namespace_capacity(struct nd_namespace_common *ndns) } EXPORT_SYMBOL(nvdimm_namespace_capacity); +bool nvdimm_namespace_locked(struct nd_namespace_common *ndns) +{ + int i; + bool locked = false; + struct device *dev = &ndns->dev; + struct nd_region *nd_region = to_nd_region(dev->parent); + + for (i = 0; i < nd_region->ndr_mappings; i++) { + struct nd_mapping *nd_mapping = &nd_region->mapping[i]; + struct nvdimm *nvdimm = nd_mapping->nvdimm; + + if (test_bit(NDD_LOCKED, &nvdimm->flags)) { + dev_dbg(dev, "%s locked\n", nvdimm_name(nvdimm)); + locked = true; + } + } + return locked; +} +EXPORT_SYMBOL(nvdimm_namespace_locked); + static ssize_t size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1695,6 +1715,9 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev) } } + if (nvdimm_namespace_locked(ndns)) + return ERR_PTR(-EACCES); + size = nvdimm_namespace_capacity(ndns); if (size < ND_MIN_NAMESPACE_SIZE) { dev_dbg(&ndns->dev, "%pa, too small must be at least %#x\n", diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 79274ead54fb..ac68072fb8cd 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -100,6 +100,14 @@ struct nd_region; struct nvdimm_drvdata; struct nd_mapping; void nd_mapping_free_labels(struct nd_mapping *nd_mapping); + +int __reserve_free_pmem(struct device *dev, void *data); +void release_free_pmem(struct nvdimm_bus *nvdimm_bus, + struct nd_mapping *nd_mapping); + +resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region, + struct nd_mapping *nd_mapping); +resource_size_t nd_region_allocatable_dpa(struct nd_region *nd_region); resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region, struct nd_mapping *nd_mapping, resource_size_t *overlap); resource_size_t nd_blk_available_dpa(struct nd_region *nd_region); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 6ee7fd7e4bbd..98317e7ce5b5 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -357,6 +357,7 @@ struct resource *nvdimm_allocate_dpa(struct nvdimm_drvdata *ndd, struct nd_label_id *label_id, resource_size_t start, resource_size_t n); resource_size_t nvdimm_namespace_capacity(struct nd_namespace_common *ndns); +bool nvdimm_namespace_locked(struct nd_namespace_common *ndns); struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev); int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns); int nvdimm_namespace_detach_btt(struct nd_btt *nd_btt); diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index dd17acd8fe68..6071e2942053 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -20,6 +20,7 @@ #include <linux/hdreg.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/set_memory.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/badblocks.h> @@ -51,6 +52,30 @@ static struct nd_region *to_region(struct pmem_device *pmem) return to_nd_region(to_dev(pmem)->parent); } +static void hwpoison_clear(struct pmem_device *pmem, + phys_addr_t phys, unsigned int len) +{ + unsigned long pfn_start, pfn_end, pfn; + + /* only pmem in the linear map supports HWPoison */ + if (is_vmalloc_addr(pmem->virt_addr)) + return; + + pfn_start = PHYS_PFN(phys); + pfn_end = pfn_start + PHYS_PFN(len); + for (pfn = pfn_start; pfn < pfn_end; pfn++) { + struct page *page = pfn_to_page(pfn); + + /* + * Note, no need to hold a get_dev_pagemap() reference + * here since we're in the driver I/O path and + * outstanding I/O requests pin the dev_pagemap. + */ + if (test_and_clear_pmem_poison(page)) + clear_mce_nospec(pfn); + } +} + static blk_status_t pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, unsigned int len) { @@ -65,6 +90,7 @@ static blk_status_t pmem_clear_poison(struct pmem_device *pmem, if (cleared < len) rc = BLK_STS_IOERR; if (cleared > 0 && cleared / 512) { + hwpoison_clear(pmem, pmem->phys_addr + offset, cleared); cleared /= 512; dev_dbg(dev, "%#llx clear %ld sector%s\n", (unsigned long long) sector, cleared, @@ -226,8 +252,11 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512, PFN_PHYS(nr_pages)))) return -EIO; - *kaddr = pmem->virt_addr + offset; - *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); + + if (kaddr) + *kaddr = pmem->virt_addr + offset; + if (pfn) + *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); /* * If badblocks are present, limit known good range to the diff --git a/drivers/nvdimm/pmem.h b/drivers/nvdimm/pmem.h index a64ebc78b5df..59cfe13ea8a8 100644 --- a/drivers/nvdimm/pmem.h +++ b/drivers/nvdimm/pmem.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __NVDIMM_PMEM_H__ #define __NVDIMM_PMEM_H__ +#include <linux/page-flags.h> #include <linux/badblocks.h> #include <linux/types.h> #include <linux/pfn_t.h> @@ -27,4 +28,16 @@ struct pmem_device { long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, long nr_pages, void **kaddr, pfn_t *pfn); + +#ifdef CONFIG_MEMORY_FAILURE +static inline bool test_and_clear_pmem_poison(struct page *page) +{ + return TestClearPageHWPoison(page); +} +#else +static inline bool test_and_clear_pmem_poison(struct page *page) +{ + return false; +} +#endif #endif /* __NVDIMM_PMEM_H__ */ diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index ec3543b83330..fa37afcd43ff 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -389,6 +389,30 @@ resource_size_t nd_region_available_dpa(struct nd_region *nd_region) return available; } +resource_size_t nd_region_allocatable_dpa(struct nd_region *nd_region) +{ + resource_size_t available = 0; + int i; + + if (is_memory(&nd_region->dev)) + available = PHYS_ADDR_MAX; + + WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev)); + for (i = 0; i < nd_region->ndr_mappings; i++) { + struct nd_mapping *nd_mapping = &nd_region->mapping[i]; + + if (is_memory(&nd_region->dev)) + available = min(available, + nd_pmem_max_contiguous_dpa(nd_region, + nd_mapping)); + else if (is_nd_blk(&nd_region->dev)) + available += nd_blk_available_dpa(nd_region); + } + if (is_memory(&nd_region->dev)) + return available * nd_region->ndr_mappings; + return available; +} + static ssize_t available_size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -410,6 +434,21 @@ static ssize_t available_size_show(struct device *dev, } static DEVICE_ATTR_RO(available_size); +static ssize_t max_available_extent_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nd_region *nd_region = to_nd_region(dev); + unsigned long long available = 0; + + nvdimm_bus_lock(dev); + wait_nvdimm_bus_probe_idle(dev); + available = nd_region_allocatable_dpa(nd_region); + nvdimm_bus_unlock(dev); + + return sprintf(buf, "%llu\n", available); +} +static DEVICE_ATTR_RO(max_available_extent); + static ssize_t init_namespaces_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -561,6 +600,7 @@ static struct attribute *nd_region_attributes[] = { &dev_attr_read_only.attr, &dev_attr_set_cookie.attr, &dev_attr_available_size.attr, + &dev_attr_max_available_extent.attr, &dev_attr_namespace_seed.attr, &dev_attr_init_namespaces.attr, &dev_attr_badblocks.attr, diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 738e3546abb1..c2ab57705043 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -615,13 +615,11 @@ static bool acpi_pci_need_resume(struct pci_dev *dev) /* * In some cases (eg. Samsung 305V4A) leaving a bridge in suspend over * system-wide suspend/resume confuses the platform firmware, so avoid - * doing that, unless the bridge has a driver that should take care of - * the PM handling. According to Section 16.1.6 of ACPI 6.2, endpoint + * doing that. According to Section 16.1.6 of ACPI 6.2, endpoint * devices are expected to be in D3 before invoking the S3 entry path * from the firmware, so they should not be affected by this issue. */ - if (pci_is_bridge(dev) && !dev->driver && - acpi_target_system_state() != ACPI_STATE_S0) + if (pci_is_bridge(dev) && acpi_target_system_state() != ACPI_STATE_S0) return true; if (!adev || !acpi_device_power_manageable(adev)) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 46f58a9771d7..ef7143a274e0 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -66,9 +66,15 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { - calltime = fixup_debug_start(dev, f->hook); - f->hook(dev); - fixup_debug_report(dev, calltime, f->hook); + void (*hook)(struct pci_dev *dev); +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS + hook = offset_to_ptr(&f->hook_offset); +#else + hook = f->hook; +#endif + calltime = fixup_debug_start(dev, hook); + hook(dev); + fixup_debug_report(dev, calltime, hook); } } diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 8d4b7e999f02..e86752be1f19 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -361,6 +361,7 @@ source "drivers/pinctrl/vt8500/Kconfig" source "drivers/pinctrl/mediatek/Kconfig" source "drivers/pinctrl/zte/Kconfig" source "drivers/pinctrl/meson/Kconfig" +source "drivers/pinctrl/cirrus/Kconfig" config PINCTRL_XWAY bool diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index de40863e7297..46ef9bd52096 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -64,3 +64,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ obj-y += mediatek/ obj-$(CONFIG_PINCTRL_ZX) += zte/ +obj-y += cirrus/ diff --git a/drivers/pinctrl/cirrus/Kconfig b/drivers/pinctrl/cirrus/Kconfig new file mode 100644 index 000000000000..27013e5949bc --- /dev/null +++ b/drivers/pinctrl/cirrus/Kconfig @@ -0,0 +1,14 @@ +# This is all selected by the Madera MFD driver Kconfig options +config PINCTRL_MADERA + tristate + select PINMUX + select GENERIC_PINCONF + +config PINCTRL_CS47L35 + bool + +config PINCTRL_CS47L85 + bool + +config PINCTRL_CS47L90 + bool diff --git a/drivers/pinctrl/cirrus/Makefile b/drivers/pinctrl/cirrus/Makefile new file mode 100644 index 000000000000..6e4938cde9e3 --- /dev/null +++ b/drivers/pinctrl/cirrus/Makefile @@ -0,0 +1,13 @@ +# Cirrus Logic pinctrl drivers +pinctrl-madera-objs := pinctrl-madera-core.o +ifeq ($(CONFIG_PINCTRL_CS47L35),y) +pinctrl-madera-objs += pinctrl-cs47l35.o +endif +ifeq ($(CONFIG_PINCTRL_CS47L85),y) +pinctrl-madera-objs += pinctrl-cs47l85.o +endif +ifeq ($(CONFIG_PINCTRL_CS47L90),y) +pinctrl-madera-objs += pinctrl-cs47l90.o +endif + +obj-$(CONFIG_PINCTRL_MADERA) += pinctrl-madera.o diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l35.c b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c new file mode 100644 index 000000000000..06b59160783d --- /dev/null +++ b/drivers/pinctrl/cirrus/pinctrl-cs47l35.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl for Cirrus Logic CS47L35 + * + * Copyright (C) 2016-2017 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/err.h> +#include <linux/mfd/madera/core.h> + +#include "pinctrl-madera.h" + +/* + * The alt func groups are the most commonly used functions we place these at + * the lower function indexes for convenience, and the less commonly used gpio + * functions at higher indexes. + * + * To stay consistent with the datasheet the function names are the same as + * the group names for that function's pins + * + * Note - all 1 less than in datasheet because these are zero-indexed + */ +static const unsigned int cs47l35_aif3_pins[] = { 0, 1, 2, 3 }; +static const unsigned int cs47l35_spk_pins[] = { 4, 5 }; +static const unsigned int cs47l35_aif1_pins[] = { 7, 8, 9, 10 }; +static const unsigned int cs47l35_aif2_pins[] = { 11, 12, 13, 14 }; +static const unsigned int cs47l35_mif1_pins[] = { 6, 15 }; + +static const struct madera_pin_groups cs47l35_pin_groups[] = { + { "aif1", cs47l35_aif1_pins, ARRAY_SIZE(cs47l35_aif1_pins) }, + { "aif2", cs47l35_aif2_pins, ARRAY_SIZE(cs47l35_aif2_pins) }, + { "aif3", cs47l35_aif3_pins, ARRAY_SIZE(cs47l35_aif3_pins) }, + { "mif1", cs47l35_mif1_pins, ARRAY_SIZE(cs47l35_mif1_pins) }, + { "pdmspk1", cs47l35_spk_pins, ARRAY_SIZE(cs47l35_spk_pins) }, +}; + +const struct madera_pin_chip cs47l35_pin_chip = { + .n_pins = CS47L35_NUM_GPIOS, + .pin_groups = cs47l35_pin_groups, + .n_pin_groups = ARRAY_SIZE(cs47l35_pin_groups), +}; diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l85.c b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c new file mode 100644 index 000000000000..0a322e2a0fde --- /dev/null +++ b/drivers/pinctrl/cirrus/pinctrl-cs47l85.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl for Cirrus Logic CS47L85 + * + * Copyright (C) 2016-2017 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/err.h> +#include <linux/mfd/madera/core.h> + +#include "pinctrl-madera.h" + +/* + * The alt func groups are the most commonly used functions we place these at + * the lower function indexes for convenience, and the less commonly used gpio + * functions at higher indexes. + * + * To stay consistent with the datasheet the function names are the same as + * the group names for that function's pins + * + * Note - all 1 less than in datasheet because these are zero-indexed + */ +static const unsigned int cs47l85_mif1_pins[] = { 8, 9 }; +static const unsigned int cs47l85_mif2_pins[] = { 10, 11 }; +static const unsigned int cs47l85_mif3_pins[] = { 12, 13 }; +static const unsigned int cs47l85_aif1_pins[] = { 14, 15, 16, 17 }; +static const unsigned int cs47l85_aif2_pins[] = { 18, 19, 20, 21 }; +static const unsigned int cs47l85_aif3_pins[] = { 22, 23, 24, 25 }; +static const unsigned int cs47l85_aif4_pins[] = { 26, 27, 28, 29 }; +static const unsigned int cs47l85_dmic4_pins[] = { 30, 31 }; +static const unsigned int cs47l85_dmic5_pins[] = { 32, 33 }; +static const unsigned int cs47l85_dmic6_pins[] = { 34, 35 }; +static const unsigned int cs47l85_spk1_pins[] = { 36, 38 }; +static const unsigned int cs47l85_spk2_pins[] = { 37, 39 }; + +static const struct madera_pin_groups cs47l85_pin_groups[] = { + { "aif1", cs47l85_aif1_pins, ARRAY_SIZE(cs47l85_aif1_pins) }, + { "aif2", cs47l85_aif2_pins, ARRAY_SIZE(cs47l85_aif2_pins) }, + { "aif3", cs47l85_aif3_pins, ARRAY_SIZE(cs47l85_aif3_pins) }, + { "aif4", cs47l85_aif4_pins, ARRAY_SIZE(cs47l85_aif4_pins) }, + { "mif1", cs47l85_mif1_pins, ARRAY_SIZE(cs47l85_mif1_pins) }, + { "mif2", cs47l85_mif2_pins, ARRAY_SIZE(cs47l85_mif2_pins) }, + { "mif3", cs47l85_mif3_pins, ARRAY_SIZE(cs47l85_mif3_pins) }, + { "dmic4", cs47l85_dmic4_pins, ARRAY_SIZE(cs47l85_dmic4_pins) }, + { "dmic5", cs47l85_dmic5_pins, ARRAY_SIZE(cs47l85_dmic5_pins) }, + { "dmic6", cs47l85_dmic6_pins, ARRAY_SIZE(cs47l85_dmic6_pins) }, + { "pdmspk1", cs47l85_spk1_pins, ARRAY_SIZE(cs47l85_spk1_pins) }, + { "pdmspk2", cs47l85_spk2_pins, ARRAY_SIZE(cs47l85_spk2_pins) }, +}; + +const struct madera_pin_chip cs47l85_pin_chip = { + .n_pins = CS47L85_NUM_GPIOS, + .pin_groups = cs47l85_pin_groups, + .n_pin_groups = ARRAY_SIZE(cs47l85_pin_groups), +}; diff --git a/drivers/pinctrl/cirrus/pinctrl-cs47l90.c b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c new file mode 100644 index 000000000000..fc38f579f492 --- /dev/null +++ b/drivers/pinctrl/cirrus/pinctrl-cs47l90.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl for Cirrus Logic CS47L90 + * + * Copyright (C) 2016-2017 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/err.h> +#include <linux/mfd/madera/core.h> + +#include "pinctrl-madera.h" + +/* + * The alt func groups are the most commonly used functions we place these at + * the lower function indexes for convenience, and the less commonly used gpio + * functions at higher indexes. + * + * To stay consistent with the datasheet the function names are the same as + * the group names for that function's pins + * + * Note - all 1 less than in datasheet because these are zero-indexed + */ +static const unsigned int cs47l90_mif1_pins[] = { 8, 9 }; +static const unsigned int cs47l90_mif2_pins[] = { 10, 11 }; +static const unsigned int cs47l90_mif3_pins[] = { 12, 13 }; +static const unsigned int cs47l90_aif1_pins[] = { 14, 15, 16, 17 }; +static const unsigned int cs47l90_aif2_pins[] = { 18, 19, 20, 21 }; +static const unsigned int cs47l90_aif3_pins[] = { 22, 23, 24, 25 }; +static const unsigned int cs47l90_aif4_pins[] = { 26, 27, 28, 29 }; +static const unsigned int cs47l90_dmic4_pins[] = { 30, 31 }; +static const unsigned int cs47l90_dmic5_pins[] = { 32, 33 }; +static const unsigned int cs47l90_dmic3_pins[] = { 34, 35 }; +static const unsigned int cs47l90_spk1_pins[] = { 36, 37 }; + +static const struct madera_pin_groups cs47l90_pin_groups[] = { + { "aif1", cs47l90_aif1_pins, ARRAY_SIZE(cs47l90_aif1_pins) }, + { "aif2", cs47l90_aif2_pins, ARRAY_SIZE(cs47l90_aif2_pins) }, + { "aif3", cs47l90_aif3_pins, ARRAY_SIZE(cs47l90_aif3_pins) }, + { "aif4", cs47l90_aif4_pins, ARRAY_SIZE(cs47l90_aif4_pins) }, + { "mif1", cs47l90_mif1_pins, ARRAY_SIZE(cs47l90_mif1_pins) }, + { "mif2", cs47l90_mif2_pins, ARRAY_SIZE(cs47l90_mif2_pins) }, + { "mif3", cs47l90_mif3_pins, ARRAY_SIZE(cs47l90_mif3_pins) }, + { "dmic3", cs47l90_dmic3_pins, ARRAY_SIZE(cs47l90_dmic3_pins) }, + { "dmic4", cs47l90_dmic4_pins, ARRAY_SIZE(cs47l90_dmic4_pins) }, + { "dmic5", cs47l90_dmic5_pins, ARRAY_SIZE(cs47l90_dmic5_pins) }, + { "pdmspk1", cs47l90_spk1_pins, ARRAY_SIZE(cs47l90_spk1_pins) }, +}; + +const struct madera_pin_chip cs47l90_pin_chip = { + .n_pins = CS47L90_NUM_GPIOS, + .pin_groups = cs47l90_pin_groups, + .n_pin_groups = ARRAY_SIZE(cs47l90_pin_groups), +}; diff --git a/drivers/pinctrl/cirrus/pinctrl-madera-core.c b/drivers/pinctrl/cirrus/pinctrl-madera-core.c new file mode 100644 index 000000000000..ece41fb2848f --- /dev/null +++ b/drivers/pinctrl/cirrus/pinctrl-madera-core.c @@ -0,0 +1,1076 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl for Cirrus Logic Madera codecs + * + * Copyright (C) 2016-2018 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#include <linux/err.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinconf-generic.h> + +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/registers.h> + +#include "../pinctrl-utils.h" + +#include "pinctrl-madera.h" + +/* + * Use pin GPIO names for consistency + * NOTE: IDs are zero-indexed for coding convenience + */ +static const struct pinctrl_pin_desc madera_pins[] = { + PINCTRL_PIN(0, "gpio1"), + PINCTRL_PIN(1, "gpio2"), + PINCTRL_PIN(2, "gpio3"), + PINCTRL_PIN(3, "gpio4"), + PINCTRL_PIN(4, "gpio5"), + PINCTRL_PIN(5, "gpio6"), + PINCTRL_PIN(6, "gpio7"), + PINCTRL_PIN(7, "gpio8"), + PINCTRL_PIN(8, "gpio9"), + PINCTRL_PIN(9, "gpio10"), + PINCTRL_PIN(10, "gpio11"), + PINCTRL_PIN(11, "gpio12"), + PINCTRL_PIN(12, "gpio13"), + PINCTRL_PIN(13, "gpio14"), + PINCTRL_PIN(14, "gpio15"), + PINCTRL_PIN(15, "gpio16"), + PINCTRL_PIN(16, "gpio17"), + PINCTRL_PIN(17, "gpio18"), + PINCTRL_PIN(18, "gpio19"), + PINCTRL_PIN(19, "gpio20"), + PINCTRL_PIN(20, "gpio21"), + PINCTRL_PIN(21, "gpio22"), + PINCTRL_PIN(22, "gpio23"), + PINCTRL_PIN(23, "gpio24"), + PINCTRL_PIN(24, "gpio25"), + PINCTRL_PIN(25, "gpio26"), + PINCTRL_PIN(26, "gpio27"), + PINCTRL_PIN(27, "gpio28"), + PINCTRL_PIN(28, "gpio29"), + PINCTRL_PIN(29, "gpio30"), + PINCTRL_PIN(30, "gpio31"), + PINCTRL_PIN(31, "gpio32"), + PINCTRL_PIN(32, "gpio33"), + PINCTRL_PIN(33, "gpio34"), + PINCTRL_PIN(34, "gpio35"), + PINCTRL_PIN(35, "gpio36"), + PINCTRL_PIN(36, "gpio37"), + PINCTRL_PIN(37, "gpio38"), + PINCTRL_PIN(38, "gpio39"), + PINCTRL_PIN(39, "gpio40"), +}; + +/* + * All single-pin functions can be mapped to any GPIO, however pinmux applies + * functions to pin groups and only those groups declared as supporting that + * function. To make this work we must put each pin in its own dummy group so + * that the functions can be described as applying to all pins. + * Since these do not correspond to anything in the actual hardware - they are + * merely an adaptation to pinctrl's view of the world - we use the same name + * as the pin to avoid confusion when comparing with datasheet instructions + */ +static const char * const madera_pin_single_group_names[] = { + "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", + "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", +}; + +/* set of pin numbers for single-pin groups, zero-indexed */ +static const unsigned int madera_pin_single_group_pins[] = { + 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, +}; + +static const char * const madera_aif1_group_names[] = { "aif1" }; +static const char * const madera_aif2_group_names[] = { "aif2" }; +static const char * const madera_aif3_group_names[] = { "aif3" }; +static const char * const madera_aif4_group_names[] = { "aif4" }; +static const char * const madera_mif1_group_names[] = { "mif1" }; +static const char * const madera_mif2_group_names[] = { "mif2" }; +static const char * const madera_mif3_group_names[] = { "mif3" }; +static const char * const madera_dmic3_group_names[] = { "dmic3" }; +static const char * const madera_dmic4_group_names[] = { "dmic4" }; +static const char * const madera_dmic5_group_names[] = { "dmic5" }; +static const char * const madera_dmic6_group_names[] = { "dmic6" }; +static const char * const madera_spk1_group_names[] = { "pdmspk1" }; +static const char * const madera_spk2_group_names[] = { "pdmspk2" }; + +/* + * alt-functions always apply to a single pin group, other functions always + * apply to all pins + */ +static const struct { + const char *name; + const char * const *group_names; + u32 func; +} madera_mux_funcs[] = { + { + .name = "aif1", + .group_names = madera_aif1_group_names, + .func = 0x000 + }, + { + .name = "aif2", + .group_names = madera_aif2_group_names, + .func = 0x000 + }, + { + .name = "aif3", + .group_names = madera_aif3_group_names, + .func = 0x000 + }, + { + .name = "aif4", + .group_names = madera_aif4_group_names, + .func = 0x000 + }, + { + .name = "mif1", + .group_names = madera_mif1_group_names, + .func = 0x000 + }, + { + .name = "mif2", + .group_names = madera_mif2_group_names, + .func = 0x000 + }, + { + .name = "mif3", + .group_names = madera_mif3_group_names, + .func = 0x000 + }, + { + .name = "dmic3", + .group_names = madera_dmic3_group_names, + .func = 0x000 + }, + { + .name = "dmic4", + .group_names = madera_dmic4_group_names, + .func = 0x000 + }, + { + .name = "dmic5", + .group_names = madera_dmic5_group_names, + .func = 0x000 + }, + { + .name = "dmic6", + .group_names = madera_dmic6_group_names, + .func = 0x000 + }, + { + .name = "pdmspk1", + .group_names = madera_spk1_group_names, + .func = 0x000 + }, + { + .name = "pdmspk2", + .group_names = madera_spk2_group_names, + .func = 0x000 + }, + { + .name = "io", + .group_names = madera_pin_single_group_names, + .func = 0x001 + }, + { + .name = "dsp-gpio", + .group_names = madera_pin_single_group_names, + .func = 0x002 + }, + { + .name = "irq1", + .group_names = madera_pin_single_group_names, + .func = 0x003 + }, + { + .name = "irq2", + .group_names = madera_pin_single_group_names, + .func = 0x004 + }, + { + .name = "fll1-clk", + .group_names = madera_pin_single_group_names, + .func = 0x010 + }, + { + .name = "fll2-clk", + .group_names = madera_pin_single_group_names, + .func = 0x011 + }, + { + .name = "fll3-clk", + .group_names = madera_pin_single_group_names, + .func = 0x012 + }, + { + .name = "fllao-clk", + .group_names = madera_pin_single_group_names, + .func = 0x013 + }, + { + .name = "fll1-lock", + .group_names = madera_pin_single_group_names, + .func = 0x018 + }, + { + .name = "fll2-lock", + .group_names = madera_pin_single_group_names, + .func = 0x019 + }, + { + .name = "fll3-lock", + .group_names = madera_pin_single_group_names, + .func = 0x01a + }, + { + .name = "fllao-lock", + .group_names = madera_pin_single_group_names, + .func = 0x01b + }, + { + .name = "opclk", + .group_names = madera_pin_single_group_names, + .func = 0x040 + }, + { + .name = "opclk-async", + .group_names = madera_pin_single_group_names, + .func = 0x041 + }, + { + .name = "pwm1", + .group_names = madera_pin_single_group_names, + .func = 0x048 + }, + { + .name = "pwm2", + .group_names = madera_pin_single_group_names, + .func = 0x049 + }, + { + .name = "spdif", + .group_names = madera_pin_single_group_names, + .func = 0x04c + }, + { + .name = "asrc1-in1-lock", + .group_names = madera_pin_single_group_names, + .func = 0x088 + }, + { + .name = "asrc1-in2-lock", + .group_names = madera_pin_single_group_names, + .func = 0x089 + }, + { + .name = "asrc2-in1-lock", + .group_names = madera_pin_single_group_names, + .func = 0x08a + }, + { + .name = "asrc2-in2-lock", + .group_names = madera_pin_single_group_names, + .func = 0x08b + }, + { + .name = "spkl-short-circuit", + .group_names = madera_pin_single_group_names, + .func = 0x0b6 + }, + { + .name = "spkr-short-circuit", + .group_names = madera_pin_single_group_names, + .func = 0x0b7 + }, + { + .name = "spk-shutdown", + .group_names = madera_pin_single_group_names, + .func = 0x0e0 + }, + { + .name = "spk-overheat-shutdown", + .group_names = madera_pin_single_group_names, + .func = 0x0e1 + }, + { + .name = "spk-overheat-warn", + .group_names = madera_pin_single_group_names, + .func = 0x0e2 + }, + { + .name = "timer1-sts", + .group_names = madera_pin_single_group_names, + .func = 0x140 + }, + { + .name = "timer2-sts", + .group_names = madera_pin_single_group_names, + .func = 0x141 + }, + { + .name = "timer3-sts", + .group_names = madera_pin_single_group_names, + .func = 0x142 + }, + { + .name = "timer4-sts", + .group_names = madera_pin_single_group_names, + .func = 0x143 + }, + { + .name = "timer5-sts", + .group_names = madera_pin_single_group_names, + .func = 0x144 + }, + { + .name = "timer6-sts", + .group_names = madera_pin_single_group_names, + .func = 0x145 + }, + { + .name = "timer7-sts", + .group_names = madera_pin_single_group_names, + .func = 0x146 + }, + { + .name = "timer8-sts", + .group_names = madera_pin_single_group_names, + .func = 0x147 + }, + { + .name = "log1-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x150 + }, + { + .name = "log2-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x151 + }, + { + .name = "log3-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x152 + }, + { + .name = "log4-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x153 + }, + { + .name = "log5-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x154 + }, + { + .name = "log6-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x155 + }, + { + .name = "log7-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x156 + }, + { + .name = "log8-fifo-ne", + .group_names = madera_pin_single_group_names, + .func = 0x157 + }, +}; + +static u16 madera_pin_make_drv_str(struct madera_pin_private *priv, + unsigned int milliamps) +{ + switch (milliamps) { + case 4: + return 0; + case 8: + return 2 << MADERA_GP1_DRV_STR_SHIFT; + default: + break; + } + + dev_warn(priv->dev, "%u mA not a valid drive strength", milliamps); + + return 0; +} + +static unsigned int madera_pin_unmake_drv_str(struct madera_pin_private *priv, + u16 regval) +{ + regval = (regval & MADERA_GP1_DRV_STR_MASK) >> MADERA_GP1_DRV_STR_SHIFT; + + switch (regval) { + case 0: + return 4; + case 2: + return 8; + default: + return 0; + } +} + +static int madera_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + + /* Number of alt function groups plus number of single-pin groups */ + return priv->chip->n_pin_groups + priv->chip->n_pins; +} + +static const char *madera_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + + if (selector < priv->chip->n_pin_groups) + return priv->chip->pin_groups[selector].name; + + selector -= priv->chip->n_pin_groups; + return madera_pin_single_group_names[selector]; +} + +static int madera_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + + if (selector < priv->chip->n_pin_groups) { + *pins = priv->chip->pin_groups[selector].pins; + *num_pins = priv->chip->pin_groups[selector].n_pins; + } else { + /* return the dummy group for a single pin */ + selector -= priv->chip->n_pin_groups; + *pins = &madera_pin_single_group_pins[selector]; + *num_pins = 1; + } + return 0; +} + +static void madera_pin_dbg_show_fn(struct madera_pin_private *priv, + struct seq_file *s, + unsigned int pin, unsigned int fn) +{ + const struct madera_pin_chip *chip = priv->chip; + int i, g_pin; + + if (fn != 0) { + for (i = 0; i < ARRAY_SIZE(madera_mux_funcs); ++i) { + if (madera_mux_funcs[i].func == fn) { + seq_printf(s, " FN=%s", + madera_mux_funcs[i].name); + return; + } + } + return; /* ignore unknown function values */ + } + + /* alt function */ + for (i = 0; i < chip->n_pin_groups; ++i) { + for (g_pin = 0; g_pin < chip->pin_groups[i].n_pins; ++g_pin) { + if (chip->pin_groups[i].pins[g_pin] == pin) { + seq_printf(s, " FN=%s", + chip->pin_groups[i].name); + return; + } + } + } +} + +static void __maybe_unused madera_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int pin) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int conf[2]; + unsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * pin); + unsigned int fn; + int ret; + + ret = regmap_read(priv->madera->regmap, reg, &conf[0]); + if (ret) + return; + + ret = regmap_read(priv->madera->regmap, reg + 1, &conf[1]); + if (ret) + return; + + seq_printf(s, "%04x:%04x", conf[0], conf[1]); + + fn = (conf[0] & MADERA_GP1_FN_MASK) >> MADERA_GP1_FN_SHIFT; + madera_pin_dbg_show_fn(priv, s, pin, fn); + + /* State of direction bit is only relevant if function==1 */ + if (fn == 1) { + if (conf[1] & MADERA_GP1_DIR_MASK) + seq_puts(s, " IN"); + else + seq_puts(s, " OUT"); + } + + if (conf[1] & MADERA_GP1_PU_MASK) + seq_puts(s, " PU"); + + if (conf[1] & MADERA_GP1_PD_MASK) + seq_puts(s, " PD"); + + if (conf[0] & MADERA_GP1_DB_MASK) + seq_puts(s, " DB"); + + if (conf[0] & MADERA_GP1_OP_CFG_MASK) + seq_puts(s, " OD"); + else + seq_puts(s, " CMOS"); + + seq_printf(s, " DRV=%umA", madera_pin_unmake_drv_str(priv, conf[1])); + + if (conf[0] & MADERA_GP1_IP_CFG_MASK) + seq_puts(s, "SCHMITT"); +} + + +static const struct pinctrl_ops madera_pin_group_ops = { + .get_groups_count = madera_get_groups_count, + .get_group_name = madera_get_group_name, + .get_group_pins = madera_get_group_pins, +#if IS_ENABLED(CONFIG_OF) + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_free_map, +#endif +#if IS_ENABLED(CONFIG_DEBUG_FS) + .pin_dbg_show = madera_pin_dbg_show, +#endif +}; + +static int madera_mux_get_funcs_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(madera_mux_funcs); +} + +static const char *madera_mux_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return madera_mux_funcs[selector].name; +} + +static int madera_mux_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + + *groups = madera_mux_funcs[selector].group_names; + + if (madera_mux_funcs[selector].func == 0) { + /* alt func always maps to a single group */ + *num_groups = 1; + } else { + /* other funcs map to all available gpio pins */ + *num_groups = priv->chip->n_pins; + } + + return 0; +} + +static int madera_mux_set_mux(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned int group) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + struct madera *madera = priv->madera; + const struct madera_pin_groups *pin_group = priv->chip->pin_groups; + unsigned int n_chip_groups = priv->chip->n_pin_groups; + const char *func_name = madera_mux_funcs[selector].name; + unsigned int reg; + int i, ret; + + dev_dbg(priv->dev, "%s selecting %u (%s) for group %u (%s)\n", + __func__, selector, func_name, group, + madera_get_group_name(pctldev, group)); + + if (madera_mux_funcs[selector].func == 0) { + /* alt func pin assignments are codec-specific */ + for (i = 0; i < n_chip_groups; ++i) { + if (strcmp(func_name, pin_group->name) == 0) + break; + + ++pin_group; + } + + if (i == n_chip_groups) + return -EINVAL; + + for (i = 0; i < pin_group->n_pins; ++i) { + reg = MADERA_GPIO1_CTRL_1 + (2 * pin_group->pins[i]); + + dev_dbg(priv->dev, "%s setting 0x%x func bits to 0\n", + __func__, reg); + + ret = regmap_update_bits(madera->regmap, reg, + MADERA_GP1_FN_MASK, 0); + if (ret) + break; + + } + } else { + /* + * for other funcs the group will be the gpio number and will + * be offset by the number of chip-specific functions at the + * start of the group list + */ + group -= n_chip_groups; + reg = MADERA_GPIO1_CTRL_1 + (2 * group); + + dev_dbg(priv->dev, "%s setting 0x%x func bits to 0x%x\n", + __func__, reg, madera_mux_funcs[selector].func); + + ret = regmap_update_bits(madera->regmap, + reg, + MADERA_GP1_FN_MASK, + madera_mux_funcs[selector].func); + } + + if (ret) + dev_err(priv->dev, "Failed to write to 0x%x (%d)\n", reg, ret); + + return ret; +} + +static int madera_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, + bool input) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + struct madera *madera = priv->madera; + unsigned int reg = MADERA_GPIO1_CTRL_2 + (2 * offset); + unsigned int val; + int ret; + + if (input) + val = MADERA_GP1_DIR; + else + val = 0; + + ret = regmap_update_bits(madera->regmap, reg, MADERA_GP1_DIR_MASK, val); + if (ret) + dev_err(priv->dev, "Failed to write to 0x%x (%d)\n", reg, ret); + + return ret; +} + +static int madera_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + struct madera *madera = priv->madera; + unsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * offset); + int ret; + + /* put the pin into GPIO mode */ + ret = regmap_update_bits(madera->regmap, reg, MADERA_GP1_FN_MASK, 1); + if (ret) + dev_err(priv->dev, "Failed to write to 0x%x (%d)\n", reg, ret); + + return ret; +} + +static void madera_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + struct madera *madera = priv->madera; + unsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * offset); + int ret; + + /* disable GPIO by setting to GPIO IN */ + madera_gpio_set_direction(pctldev, range, offset, true); + + ret = regmap_update_bits(madera->regmap, reg, MADERA_GP1_FN_MASK, 1); + if (ret) + dev_err(priv->dev, "Failed to write to 0x%x (%d)\n", reg, ret); +} + +static const struct pinmux_ops madera_pin_mux_ops = { + .get_functions_count = madera_mux_get_funcs_count, + .get_function_name = madera_mux_get_func_name, + .get_function_groups = madera_mux_get_groups, + .set_mux = madera_mux_set_mux, + .gpio_request_enable = madera_gpio_request_enable, + .gpio_disable_free = madera_gpio_disable_free, + .gpio_set_direction = madera_gpio_set_direction, + .strict = true, /* GPIO and other functions are exclusive */ +}; + +static int madera_pin_conf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int param = pinconf_to_config_param(*config); + unsigned int result = 0; + unsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * pin); + unsigned int conf[2]; + int ret; + + ret = regmap_read(priv->madera->regmap, reg, &conf[0]); + if (!ret) + ret = regmap_read(priv->madera->regmap, reg + 1, &conf[1]); + + if (ret) { + dev_err(priv->dev, "Failed to read GP%d conf (%d)\n", + pin + 1, ret); + return ret; + } + + switch (param) { + case PIN_CONFIG_BIAS_BUS_HOLD: + conf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + if (conf[1] == (MADERA_GP1_PU | MADERA_GP1_PD)) + result = 1; + break; + case PIN_CONFIG_BIAS_DISABLE: + conf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + if (!conf[1]) + result = 1; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + conf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + if (conf[1] == MADERA_GP1_PD_MASK) + result = 1; + break; + case PIN_CONFIG_BIAS_PULL_UP: + conf[1] &= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + if (conf[1] == MADERA_GP1_PU_MASK) + result = 1; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (conf[0] & MADERA_GP1_OP_CFG_MASK) + result = 1; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (!(conf[0] & MADERA_GP1_OP_CFG_MASK)) + result = 1; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + result = madera_pin_unmake_drv_str(priv, conf[1]); + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + if (conf[0] & MADERA_GP1_DB_MASK) + result = 1; + break; + case PIN_CONFIG_INPUT_ENABLE: + if (conf[0] & MADERA_GP1_DIR_MASK) + result = 1; + break; + case PIN_CONFIG_INPUT_SCHMITT: + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (conf[0] & MADERA_GP1_IP_CFG_MASK) + result = 1; + break; + case PIN_CONFIG_OUTPUT: + if ((conf[1] & MADERA_GP1_DIR_MASK) && + (conf[0] & MADERA_GP1_LVL_MASK)) + result = 1; + break; + default: + break; + } + + *config = pinconf_to_config_packed(param, result); + + return 0; +} + +static int madera_pin_conf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + u16 conf[2] = {0, 0}; + u16 mask[2] = {0, 0}; + unsigned int reg = MADERA_GPIO1_CTRL_1 + (2 * pin); + unsigned int val; + int ret; + + while (num_configs) { + dev_dbg(priv->dev, "%s config 0x%lx\n", __func__, *configs); + + switch (pinconf_to_config_param(*configs)) { + case PIN_CONFIG_BIAS_BUS_HOLD: + mask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + conf[1] |= MADERA_GP1_PU | MADERA_GP1_PD; + break; + case PIN_CONFIG_BIAS_DISABLE: + mask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + conf[1] &= ~(MADERA_GP1_PU | MADERA_GP1_PD); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + mask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + conf[1] |= MADERA_GP1_PD; + conf[1] &= ~MADERA_GP1_PU; + break; + case PIN_CONFIG_BIAS_PULL_UP: + mask[1] |= MADERA_GP1_PU_MASK | MADERA_GP1_PD_MASK; + conf[1] |= MADERA_GP1_PU; + conf[1] &= ~MADERA_GP1_PD; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + mask[0] |= MADERA_GP1_OP_CFG_MASK; + conf[0] |= MADERA_GP1_OP_CFG; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + mask[0] |= MADERA_GP1_OP_CFG_MASK; + conf[0] &= ~MADERA_GP1_OP_CFG; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + val = pinconf_to_config_argument(*configs); + mask[1] |= MADERA_GP1_DRV_STR_MASK; + conf[1] &= ~MADERA_GP1_DRV_STR_MASK; + conf[1] |= madera_pin_make_drv_str(priv, val); + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + mask[0] |= MADERA_GP1_DB_MASK; + + /* + * we can't configure debounce time per-pin so value + * is just a flag + */ + val = pinconf_to_config_argument(*configs); + if (val) + conf[0] |= MADERA_GP1_DB; + else + conf[0] &= ~MADERA_GP1_DB; + break; + case PIN_CONFIG_INPUT_ENABLE: + val = pinconf_to_config_argument(*configs); + mask[1] |= MADERA_GP1_DIR_MASK; + if (val) + conf[1] |= MADERA_GP1_DIR; + else + conf[1] &= ~MADERA_GP1_DIR; + break; + case PIN_CONFIG_INPUT_SCHMITT: + val = pinconf_to_config_argument(*configs); + mask[0] |= MADERA_GP1_IP_CFG; + if (val) + conf[0] |= MADERA_GP1_IP_CFG; + else + conf[0] &= ~MADERA_GP1_IP_CFG; + + mask[1] |= MADERA_GP1_DIR_MASK; + conf[1] |= MADERA_GP1_DIR; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + mask[0] |= MADERA_GP1_IP_CFG; + conf[0] |= MADERA_GP1_IP_CFG; + mask[1] |= MADERA_GP1_DIR_MASK; + conf[1] |= MADERA_GP1_DIR; + break; + case PIN_CONFIG_OUTPUT: + val = pinconf_to_config_argument(*configs); + mask[0] |= MADERA_GP1_LVL_MASK; + if (val) + conf[0] |= MADERA_GP1_LVL; + else + conf[0] &= ~MADERA_GP1_LVL; + + mask[1] |= MADERA_GP1_DIR_MASK; + conf[1] &= ~MADERA_GP1_DIR; + break; + default: + break; + } + + ++configs; + --num_configs; + } + + dev_dbg(priv->dev, + "%s gpio%d 0x%x:0x%x 0x%x:0x%x\n", + __func__, pin + 1, reg, conf[0], reg + 1, conf[1]); + + ret = regmap_update_bits(priv->madera->regmap, reg, mask[0], conf[0]); + if (ret) + goto err; + + ++reg; + ret = regmap_update_bits(priv->madera->regmap, reg, mask[1], conf[1]); + if (ret) + goto err; + + return 0; + +err: + dev_err(priv->dev, + "Failed to write GPIO%d conf (%d) reg 0x%x\n", + pin + 1, ret, reg); + + return ret; +} + +static int madera_pin_conf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + struct madera_pin_private *priv = pinctrl_dev_get_drvdata(pctldev); + const struct madera_pin_groups *pin_group; + unsigned int n_groups = priv->chip->n_pin_groups; + int i, ret; + + dev_dbg(priv->dev, "%s setting group %s\n", __func__, + madera_get_group_name(pctldev, selector)); + + if (selector >= n_groups) { + /* group is a single pin, convert to pin number and set */ + return madera_pin_conf_set(pctldev, + selector - n_groups, + configs, + num_configs); + } else { + pin_group = &priv->chip->pin_groups[selector]; + + for (i = 0; i < pin_group->n_pins; ++i) { + ret = madera_pin_conf_set(pctldev, + pin_group->pins[i], + configs, + num_configs); + if (ret) + return ret; + } + } + + return 0; +} + +static const struct pinconf_ops madera_pin_conf_ops = { + .pin_config_get = madera_pin_conf_get, + .pin_config_set = madera_pin_conf_set, + .pin_config_group_set = madera_pin_conf_group_set, + +}; + +static struct pinctrl_desc madera_pin_desc = { + .name = "madera-pinctrl", + .pins = madera_pins, + .pctlops = &madera_pin_group_ops, + .pmxops = &madera_pin_mux_ops, + .confops = &madera_pin_conf_ops, + .owner = THIS_MODULE, +}; + +static int madera_pin_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + const struct madera_pdata *pdata = dev_get_platdata(madera->dev); + struct madera_pin_private *priv; + int ret; + + BUILD_BUG_ON(ARRAY_SIZE(madera_pin_single_group_names) != + ARRAY_SIZE(madera_pin_single_group_pins)); + + dev_dbg(&pdev->dev, "%s\n", __func__); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->madera = madera; + pdev->dev.of_node = madera->dev->of_node; + + switch (madera->type) { + case CS47L35: + if (IS_ENABLED(CONFIG_PINCTRL_CS47L35)) + priv->chip = &cs47l35_pin_chip; + break; + case CS47L85: + case WM1840: + if (IS_ENABLED(CONFIG_PINCTRL_CS47L85)) + priv->chip = &cs47l85_pin_chip; + break; + case CS47L90: + case CS47L91: + if (IS_ENABLED(CONFIG_PINCTRL_CS47L90)) + priv->chip = &cs47l90_pin_chip; + break; + default: + break; + } + + if (!priv->chip) + return -ENODEV; + + madera_pin_desc.npins = priv->chip->n_pins; + + ret = devm_pinctrl_register_and_init(&pdev->dev, + &madera_pin_desc, + priv, + &priv->pctl); + if (ret) { + dev_err(priv->dev, "Failed pinctrl register (%d)\n", ret); + return ret; + } + + /* if the configuration is provided through pdata, apply it */ + if (pdata) { + ret = pinctrl_register_mappings(pdata->gpio_configs, + pdata->n_gpio_configs); + if (ret) { + dev_err(priv->dev, + "Failed to register pdata mappings (%d)\n", + ret); + return ret; + } + } + + ret = pinctrl_enable(priv->pctl); + if (ret) { + dev_err(priv->dev, "Failed to enable pinctrl (%d)\n", ret); + return ret; + } + + dev_dbg(priv->dev, "pinctrl probed ok\n"); + + return 0; +} + +static struct platform_driver madera_pin_driver = { + .probe = madera_pin_probe, + .driver = { + .name = "madera-pinctrl", + }, +}; + +module_platform_driver(madera_pin_driver); + +MODULE_DESCRIPTION("Madera pinctrl driver"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/cirrus/pinctrl-madera.h b/drivers/pinctrl/cirrus/pinctrl-madera.h new file mode 100644 index 000000000000..8000f4f832a1 --- /dev/null +++ b/drivers/pinctrl/cirrus/pinctrl-madera.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl for Cirrus Logic Madera codecs + * + * Copyright (C) 2016-2017 Cirrus Logic + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2. + */ + +#ifndef PINCTRL_MADERA_H +#define PINCTRL_MADERA_H + +struct madera_pin_groups { + const char *name; + const unsigned int *pins; + unsigned int n_pins; +}; + +struct madera_pin_chip { + unsigned int n_pins; + + const struct madera_pin_groups *pin_groups; + unsigned int n_pin_groups; +}; + +struct madera_pin_private { + struct madera *madera; + + const struct madera_pin_chip *chip; /* chip-specific groups */ + + struct device *dev; + struct pinctrl_dev *pctl; +}; + +extern const struct madera_pin_chip cs47l35_pin_chip; +extern const struct madera_pin_chip cs47l85_pin_chip; +extern const struct madera_pin_chip cs47l90_pin_chip; + +#endif diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index cb0df9eb3e0f..16b1615958aa 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -52,6 +52,26 @@ config CHROMEOS_TBMC config CROS_EC_CTL tristate +config CROS_EC_I2C + tristate "ChromeOS Embedded Controller (I2C)" + depends on MFD_CROS_EC && I2C + + help + If you say Y here, you get support for talking to the ChromeOS + EC through an I2C bus. This uses a simple byte-level protocol with + a checksum. Failing accesses will be retried three times to + improve reliability. + +config CROS_EC_SPI + tristate "ChromeOS Embedded Controller (SPI)" + depends on MFD_CROS_EC && SPI + + ---help--- + If you say Y here, you get support for talking to the ChromeOS EC + through a SPI bus, using a byte-level protocol. Since the EC's + response time cannot be guaranteed, we support ignoring + 'pre-amble' bytes before the response actually starts. + config CROS_EC_LPC tristate "ChromeOS Embedded Controller (LPC)" depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST) diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index e44c37a63fa9..cd591bf872bb 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -6,6 +6,8 @@ obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \ cros_ec_vbc.o cros_ec_debugfs.o obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o +obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o +obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c index b935df6a9694..1e81f8144c0d 100644 --- a/drivers/platform/chrome/chromeos_tbmc.c +++ b/drivers/platform/chrome/chromeos_tbmc.c @@ -1,8 +1,16 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0 // Driver to detect Tablet Mode for ChromeOS convertible. // // Copyright (C) 2017 Google, Inc. // Author: Gwendal Grignou <gwendal@chromium.org> +// +// On Chromebook using ACPI, this device listens for notification +// from GOOG0006 and issue method TBMC to retrieve the status. +// +// GOOG0006 issues the notification when it receives EC_HOST_EVENT_MODE_CHANGE +// from the EC. +// Method TBMC reads EC_ACPI_MEM_DEVICE_ORIENTATION byte from the shared +// memory region. #include <linux/acpi.h> #include <linux/input.h> diff --git a/drivers/mfd/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c index ef9b4763356f..ef9b4763356f 100644 --- a/drivers/mfd/cros_ec_i2c.c +++ b/drivers/platform/chrome/cros_ec_i2c.c diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 8350ca2311c7..398393ab5df8 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -506,10 +506,31 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev, } EXPORT_SYMBOL(cros_ec_cmd_xfer_status); +static int get_next_event_xfer(struct cros_ec_device *ec_dev, + struct cros_ec_command *msg, + int version, uint32_t size) +{ + int ret; + + msg->version = version; + msg->command = EC_CMD_GET_NEXT_EVENT; + msg->insize = size; + msg->outsize = 0; + + ret = cros_ec_cmd_xfer(ec_dev, msg); + if (ret > 0) { + ec_dev->event_size = ret - 1; + memcpy(&ec_dev->event_data, msg->data, ec_dev->event_size); + } + + return ret; +} + static int get_next_event(struct cros_ec_device *ec_dev) { u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)]; struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; + static int cmd_version = 1; int ret; if (ec_dev->suspended) { @@ -517,18 +538,19 @@ static int get_next_event(struct cros_ec_device *ec_dev) return -EHOSTDOWN; } - msg->version = 0; - msg->command = EC_CMD_GET_NEXT_EVENT; - msg->insize = sizeof(ec_dev->event_data); - msg->outsize = 0; + if (cmd_version == 1) { + ret = get_next_event_xfer(ec_dev, msg, cmd_version, + sizeof(struct ec_response_get_next_event_v1)); + if (ret < 0 || msg->result != EC_RES_INVALID_VERSION) + return ret; - ret = cros_ec_cmd_xfer(ec_dev, msg); - if (ret > 0) { - ec_dev->event_size = ret - 1; - memcpy(&ec_dev->event_data, msg->data, - sizeof(ec_dev->event_data)); + /* Fallback to version 0 for future send attempts */ + cmd_version = 0; } + ret = get_next_event_xfer(ec_dev, msg, cmd_version, + sizeof(struct ec_response_get_next_event)); + return ret; } diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c index 2060d1483043..2060d1483043 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/platform/chrome/cros_ec_spi.c diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig index 591bccdeaff9..cd8a90846063 100644 --- a/drivers/platform/mellanox/Kconfig +++ b/drivers/platform/mellanox/Kconfig @@ -23,4 +23,15 @@ config MLXREG_HOTPLUG This driver handles hot-plug events for the power suppliers, power cables and fans on the wide range Mellanox IB and Ethernet systems. +config MLXREG_IO + tristate "Mellanox platform register access driver support" + depends on REGMAP + depends on HWMON + help + This driver allows access to Mellanox programmable device register + space through sysfs interface. The sets of registers for sysfs access + are defined per system type bases and include the registers related + to system resets operation, system reset causes monitoring and some + kinds of mux selection. + endif # MELLANOX_PLATFORM diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile index 7c8385e497a8..57074d9c722c 100644 --- a/drivers/platform/mellanox/Makefile +++ b/drivers/platform/mellanox/Makefile @@ -4,3 +4,4 @@ # Mellanox Platform-Specific Drivers # obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o +obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index ac97aa020db3..b6d44550d98c 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -50,9 +50,8 @@ #define MLXREG_HOTPLUG_MASK_OFF 2 #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 -/* ASIC health parameters. */ -#define MLXREG_HOTPLUG_HEALTH_MASK 0x02 -#define MLXREG_HOTPLUG_RST_CNTR 3 +/* ASIC good health mask. */ +#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02 #define MLXREG_HOTPLUG_ATTRS_MAX 24 #define MLXREG_HOTPLUG_NOT_ASSERT 3 @@ -103,6 +102,9 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, { struct mlxreg_core_hotplug_platform_data *pdata; + /* Notify user by sending hwmon uevent. */ + kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE); + /* * Return if adapter number is negative. It could be in case hotplug * event is not associated with hotplug device. @@ -134,8 +136,13 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, return 0; } -static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) +static void +mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv, + struct mlxreg_core_data *data) { + /* Notify user by sending hwmon uevent. */ + kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE); + if (data->hpdev.client) { i2c_unregister_device(data->hpdev.client); data->hpdev.client = NULL; @@ -278,14 +285,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, data = item->data + bit; if (regval & BIT(bit)) { if (item->inversed) - mlxreg_hotplug_device_destroy(data); + mlxreg_hotplug_device_destroy(priv, data); else mlxreg_hotplug_device_create(priv, data); } else { if (item->inversed) mlxreg_hotplug_device_create(priv, data); else - mlxreg_hotplug_device_destroy(data); + mlxreg_hotplug_device_destroy(priv, data); } } @@ -325,21 +332,40 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, goto out; regval &= data->mask; - item->cache = regval; - if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { - if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) || - !priv->after_probe) { + + if (item->cache == regval) + goto ack_event; + + /* + * ASIC health indication is provided through two bits. Bits + * value 0x2 indicates that ASIC reached the good health, value + * 0x0 indicates ASIC the bad health or dormant state and value + * 0x3 indicates the booting state. During ASIC reset it should + * pass the following states: dormant -> booting -> good. + */ + if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) { + if (!data->attached) { + /* + * ASIC is in steady state. Connect associated + * device, if configured. + */ mlxreg_hotplug_device_create(priv, data); data->attached = true; } } else { if (data->attached) { - mlxreg_hotplug_device_destroy(data); + /* + * ASIC health is failed after ASIC has been + * in steady state. Disconnect associated + * device, if it has been connected. + */ + mlxreg_hotplug_device_destroy(priv, data); data->attached = false; data->health_cntr = 0; } } - + item->cache = regval; +ack_event: /* Acknowledge event. */ ret = regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_EVENT_OFF, 0); @@ -551,7 +577,7 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) /* Remove all the attached devices in group. */ count = item->count; for (j = 0; j < count; j++, data++) - mlxreg_hotplug_device_destroy(data); + mlxreg_hotplug_device_destroy(priv, data); } } @@ -616,10 +642,6 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) disable_irq(priv->irq); spin_lock_init(&priv->lock); INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); - /* Perform initial interrupts setup. */ - mlxreg_hotplug_set_irq(priv); - - priv->after_probe = true; dev_set_drvdata(&pdev->dev, priv); err = mlxreg_hotplug_attr_init(priv); @@ -637,6 +659,10 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) return PTR_ERR(priv->hwmon); } + /* Perform initial interrupts setup. */ + mlxreg_hotplug_set_irq(priv); + priv->after_probe = true; + return 0; } diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c new file mode 100644 index 000000000000..acfaf64ffde6 --- /dev/null +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mellanox register access driver + * + * Copyright (C) 2018 Mellanox Technologies + * Copyright (C) 2018 Vadim Pasternak <vadimp@mellanox.com> + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_data/mlxreg.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +/* Attribute parameters. */ +#define MLXREG_IO_ATT_SIZE 10 +#define MLXREG_IO_ATT_NUM 48 + +/** + * struct mlxreg_io_priv_data - driver's private data: + * + * @pdev: platform device; + * @pdata: platform data; + * @hwmon: hwmon device; + * @mlxreg_io_attr: sysfs attributes array; + * @mlxreg_io_dev_attr: sysfs sensor device attribute array; + * @group: sysfs attribute group; + * @groups: list of sysfs attribute group for hwmon registration; + */ +struct mlxreg_io_priv_data { + struct platform_device *pdev; + struct mlxreg_core_platform_data *pdata; + struct device *hwmon; + struct attribute *mlxreg_io_attr[MLXREG_IO_ATT_NUM + 1]; + struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM]; + struct attribute_group group; + const struct attribute_group *groups[2]; +}; + +static int +mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val, + bool rw_flag, u32 *regval) +{ + int ret; + + ret = regmap_read(regmap, data->reg, regval); + if (ret) + goto access_error; + + /* + * There are three kinds of attributes: single bit, full register's + * bits and bit sequence. For the first kind field mask indicates which + * bits are not related and field bit is set zero. For the second kind + * field mask is set to zero and field bit is set with all bits one. + * No special handling for such kind of attributes - pass value as is. + * For the third kind, field mask indicates which bits are related and + * field bit is set to the first bit number (from 1 to 32) is the bit + * sequence. + */ + if (!data->bit) { + /* Single bit. */ + if (rw_flag) { + /* For show: expose effective bit value as 0 or 1. */ + *regval = !!(*regval & ~data->mask); + } else { + /* For store: set effective bit value. */ + *regval &= data->mask; + if (in_val) + *regval |= ~data->mask; + } + } else if (data->mask) { + /* Bit sequence. */ + if (rw_flag) { + /* For show: mask and shift right. */ + *regval = ror32(*regval & data->mask, (data->bit - 1)); + } else { + /* For store: shift to the position and mask. */ + in_val = rol32(in_val, data->bit - 1) & data->mask; + /* Clear relevant bits and set them to new value. */ + *regval = (*regval & ~data->mask) | in_val; + } + } + +access_error: + return ret; +} + +static ssize_t +mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(attr)->index; + struct mlxreg_core_data *data = priv->pdata->data + index; + u32 regval = 0; + int ret; + + ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, ®val); + if (ret) + goto access_error; + + return sprintf(buf, "%u\n", regval); + +access_error: + return ret; +} + +static ssize_t +mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(attr)->index; + struct mlxreg_core_data *data = priv->pdata->data + index; + u32 input_val, regval; + int ret; + + if (len > MLXREG_IO_ATT_SIZE) + return -EINVAL; + + /* Convert buffer to input value. */ + ret = kstrtou32(buf, len, &input_val); + if (ret) + return ret; + + ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false, + ®val); + if (ret) + goto access_error; + + ret = regmap_write(priv->pdata->regmap, data->reg, regval); + if (ret) + goto access_error; + + return len; + +access_error: + dev_err(&priv->pdev->dev, "Bus access error\n"); + return ret; +} + +static struct device_attribute mlxreg_io_devattr_rw = { + .show = mlxreg_io_attr_show, + .store = mlxreg_io_attr_store, +}; + +static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) +{ + int i; + + priv->group.attrs = devm_kcalloc(&priv->pdev->dev, + priv->pdata->counter, + sizeof(struct attribute *), + GFP_KERNEL); + if (!priv->group.attrs) + return -ENOMEM; + + for (i = 0; i < priv->pdata->counter; i++) { + priv->mlxreg_io_attr[i] = + &priv->mlxreg_io_dev_attr[i].dev_attr.attr; + memcpy(&priv->mlxreg_io_dev_attr[i].dev_attr, + &mlxreg_io_devattr_rw, sizeof(struct device_attribute)); + + /* Set attribute name as a label. */ + priv->mlxreg_io_attr[i]->name = + devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, + priv->pdata->data[i].label); + + if (!priv->mlxreg_io_attr[i]->name) { + dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", + i + 1); + return -ENOMEM; + } + + priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode = + priv->pdata->data[i].mode; + priv->mlxreg_io_dev_attr[i].dev_attr.attr.name = + priv->mlxreg_io_attr[i]->name; + priv->mlxreg_io_dev_attr[i].index = i; + sysfs_attr_init(&priv->mlxreg_io_dev_attr[i].dev_attr.attr); + } + + priv->group.attrs = priv->mlxreg_io_attr; + priv->groups[0] = &priv->group; + priv->groups[1] = NULL; + + return 0; +} + +static int mlxreg_io_probe(struct platform_device *pdev) +{ + struct mlxreg_io_priv_data *priv; + int err; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdata = dev_get_platdata(&pdev->dev); + if (!priv->pdata) { + dev_err(&pdev->dev, "Failed to get platform data.\n"); + return -EINVAL; + } + + priv->pdev = pdev; + + err = mlxreg_io_attr_init(priv); + if (err) { + dev_err(&priv->pdev->dev, "Failed to allocate attributes: %d\n", + err); + return err; + } + + priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, + "mlxreg_io", + priv, + priv->groups); + if (IS_ERR(priv->hwmon)) { + dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", + PTR_ERR(priv->hwmon)); + return PTR_ERR(priv->hwmon); + } + + dev_set_drvdata(&pdev->dev, priv); + + return 0; +} + +static struct platform_driver mlxreg_io_driver = { + .driver = { + .name = "mlxreg-io", + }, + .probe = mlxreg_io_probe, +}; + +module_platform_driver(mlxreg_io_driver); + +MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); +MODULE_DESCRIPTION("Mellanox regmap I/O access driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mlxreg-io"); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 107d336453b2..0c1aa6c314f5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1196,16 +1196,16 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. -config SILEAD_DMI - bool "Tablets with Silead touchscreens" +config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- - Certain ACPI based tablets with Silead touchscreens do not have - enough data in ACPI tables for the touchscreen driver to handle - the touchscreen properly, as OEMs expected the data to be baked - into the tablet model specific version of the driver shipped - with the OS-image for the device. This option supplies the missing - information. Enable this for x86 tablets with Silead touchscreens. + Certain ACPI based tablets with e.g. Silead or Chipone touchscreens + do not have enough data in ACPI tables for the touchscreen driver to + handle the touchscreen properly, as OEMs expect the data to be baked + into the tablet model specific version of the driver shipped with the + the OS-image for the device. This option supplies the missing info. + Enable this for x86 tablets with Silead or Chipone touchscreens. config INTEL_CHTDC_TI_PWRBTN tristate "Intel Cherry Trail Dollar Cove TI power button driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 50dc8f280914..e6d1becf81ce 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o -obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o +obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 8952173dd380..fcfeadd1301f 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -672,10 +672,7 @@ static void __init find_quirks(void) static bool has_cap(u32 cap) { - if ((interface->capability & cap) != 0) - return 1; - - return 0; + return interface->capability & cap; } /* @@ -2216,7 +2213,7 @@ static int __init acer_wmi_init(void) if (wmi_has_guid(AMW0_GUID1) && !dmi_check_system(amw0_whitelist) && quirks == &quirk_unknown) { - pr_err("Unsupported machine has AMW0_GUID1, unable to load\n"); + pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n"); return -ENODEV; } diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 136ff2b4cce5..db2af09067db 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -496,6 +496,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ + { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ { KE_END, 0}, }; diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 6afd011de9e5..7458f7602d5e 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -52,13 +52,12 @@ static const struct acpi_device_id device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, device_ids); -static u64 asus_wireless_method(acpi_handle handle, const char *method, - int param) +static acpi_status asus_wireless_method(acpi_handle handle, const char *method, + int param, u64 *ret) { struct acpi_object_list p; union acpi_object obj; acpi_status s; - u64 ret; acpi_handle_debug(handle, "Evaluating method %s, parameter %#x\n", method, param); @@ -67,24 +66,27 @@ static u64 asus_wireless_method(acpi_handle handle, const char *method, p.count = 1; p.pointer = &obj; - s = acpi_evaluate_integer(handle, (acpi_string) method, &p, &ret); + s = acpi_evaluate_integer(handle, (acpi_string) method, &p, ret); if (ACPI_FAILURE(s)) acpi_handle_err(handle, "Failed to eval method %s, param %#x (%d)\n", method, param, s); - acpi_handle_debug(handle, "%s returned %#llx\n", method, ret); - return ret; + else + acpi_handle_debug(handle, "%s returned %#llx\n", method, *ret); + + return s; } static enum led_brightness led_state_get(struct led_classdev *led) { struct asus_wireless_data *data; - int s; + acpi_status s; + u64 ret; data = container_of(led, struct asus_wireless_data, led); s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC", - data->hswc_params->status); - if (s == data->hswc_params->on) + data->hswc_params->status, &ret); + if (ACPI_SUCCESS(s) && ret == data->hswc_params->on) return LED_FULL; return LED_OFF; } @@ -92,10 +94,11 @@ static enum led_brightness led_state_get(struct led_classdev *led) static void led_state_update(struct work_struct *work) { struct asus_wireless_data *data; + u64 ret; data = container_of(work, struct asus_wireless_data, led_work); asus_wireless_method(acpi_device_handle(data->adev), "HSWC", - data->led_state); + data->led_state, &ret); } static void led_state_set(struct led_classdev *led, enum led_brightness value) @@ -167,6 +170,7 @@ static int asus_wireless_add(struct acpi_device *adev) data->led.brightness_get = led_state_get; data->led.flags = LED_CORE_SUSPENDRESUME; data->led.max_brightness = 1; + data->led.default_trigger = "rfkill-none"; err = devm_led_classdev_register(&adev->dev, &data->led); if (err) destroy_workqueue(data->wq); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d67f32a29bb4..2d6e272315a8 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -67,6 +67,7 @@ MODULE_LICENSE("GPL"); #define NOTIFY_BRNDOWN_MAX 0x2e #define NOTIFY_KBD_BRTUP 0xc4 #define NOTIFY_KBD_BRTDWN 0xc5 +#define NOTIFY_KBD_BRTTOGGLE 0xc7 /* WMI Methods */ #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ @@ -470,6 +471,7 @@ static void kbd_led_update(struct work_struct *work) ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); + led_classdev_notify_brightness_hw_changed(&asus->kbd_led, asus->kbd_led_wk); } static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) @@ -500,15 +502,16 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) return retval; } -static void kbd_led_set(struct led_classdev *led_cdev, - enum led_brightness value) +static void do_kbd_led_set(struct led_classdev *led_cdev, int value) { struct asus_wmi *asus; + int max_level; asus = container_of(led_cdev, struct asus_wmi, kbd_led); + max_level = asus->kbd_led.max_brightness; - if (value > asus->kbd_led.max_brightness) - value = asus->kbd_led.max_brightness; + if (value > max_level) + value = max_level; else if (value < 0) value = 0; @@ -516,6 +519,12 @@ static void kbd_led_set(struct led_classdev *led_cdev, queue_work(asus->led_workqueue, &asus->kbd_led_work); } +static void kbd_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + do_kbd_led_set(led_cdev, value); +} + static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) { struct asus_wmi *asus; @@ -666,6 +675,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus) asus->kbd_led_wk = led_val; asus->kbd_led.name = "asus::kbd_backlight"; + asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; asus->kbd_led.brightness_set = kbd_led_set; asus->kbd_led.brightness_get = kbd_led_get; asus->kbd_led.max_brightness = 3; @@ -1754,6 +1764,22 @@ static void asus_wmi_notify(u32 value, void *context) } } + if (code == NOTIFY_KBD_BRTUP) { + do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1); + goto exit; + } + if (code == NOTIFY_KBD_BRTDWN) { + do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk - 1); + goto exit; + } + if (code == NOTIFY_KBD_BRTTOGGLE) { + if (asus->kbd_led_wk == asus->kbd_led.max_brightness) + do_kbd_led_set(&asus->kbd_led, 0); + else + do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1); + goto exit; + } + if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle) goto exit; diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 9dc282ed5a9e..0537d44d45a6 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -212,6 +212,12 @@ int dell_smbios_call_filter(struct device *d, if ((buffer->cmd_class == CLASS_TOKEN_READ || buffer->cmd_class == CLASS_TOKEN_WRITE) && buffer->cmd_select < 3) { + /* tokens enabled ? */ + if (!da_tokens) { + dev_dbg(d, "no token support on this system\n"); + return -EINVAL; + } + /* find the matching token ID */ for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].location != buffer->input[0]) @@ -315,6 +321,9 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid) { int i; + if (!da_tokens) + return NULL; + for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].tokenID == tokenid) return &da_tokens[i]; @@ -565,11 +574,6 @@ static int __init dell_smbios_init(void) dmi_walk(find_tokens, NULL); - if (!da_tokens) { - pr_info("Unable to find dmi tokens\n"); - return -ENODEV; - } - ret = platform_driver_register(&platform_driver); if (ret) goto fail_platform_driver; @@ -583,13 +587,6 @@ static int __init dell_smbios_init(void) if (ret) goto fail_platform_device_add; - /* duplicate tokens will cause problems building sysfs files */ - zero_duplicates(&platform_device->dev); - - ret = build_tokens_sysfs(platform_device); - if (ret) - goto fail_create_group; - /* register backends */ wmi = init_dell_smbios_wmi(); if (wmi) @@ -600,7 +597,16 @@ static int __init dell_smbios_init(void) if (wmi && smm) { pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", wmi, smm); - goto fail_sysfs; + goto fail_create_group; + } + + if (da_tokens) { + /* duplicate tokens will cause problems building sysfs files */ + zero_duplicates(&platform_device->dev); + + ret = build_tokens_sysfs(platform_device); + if (ret) + goto fail_sysfs; } return 0; @@ -628,7 +634,8 @@ static void __exit dell_smbios_exit(void) exit_dell_smbios_smm(); mutex_lock(&smbios_mutex); if (platform_device) { - free_group(platform_device); + if (da_tokens) + free_group(platform_device); platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); } diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c index e9e9da556318..97a90bebc360 100644 --- a/drivers/platform/x86/dell-smbios-smm.c +++ b/drivers/platform/x86/dell-smbios-smm.c @@ -24,7 +24,7 @@ static int da_command_address; static int da_command_code; static struct calling_interface_buffer *buffer; -struct platform_device *platform_device; +static struct platform_device *platform_device; static DEFINE_MUTEX(smm_mutex); static const struct dmi_system_id dell_device_table[] __initconst = { @@ -82,7 +82,7 @@ static void find_cmd_address(const struct dmi_header *dm, void *dummy) } } -int dell_smbios_smm_call(struct calling_interface_buffer *input) +static int dell_smbios_smm_call(struct calling_interface_buffer *input) { struct smi_cmd command; size_t size; diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index fbefedb1c172..88afe5651d24 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -82,7 +82,7 @@ static int run_smbios_call(struct wmi_device *wdev) return 0; } -int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) +static int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) { struct wmi_smbios_priv *priv; size_t difference; diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 45b7cb01f410..d4f1259ff5a2 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1133,10 +1133,17 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { - .ident = "Lenovo Legion Y520-15IKBN", + .ident = "Lenovo Legion Y520-15IKB", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKB"), + }, + }, + { + .ident = "Lenovo Y520-15IKBM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBM"), }, }, { @@ -1154,6 +1161,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { + .ident = "Lenovo Y720-15IKBM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBM"), + }, + }, + { .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index b5adba227783..6cf9b7fa5bf0 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -96,13 +96,140 @@ struct intel_hid_priv { bool wakeup_mode; }; -static int intel_hid_set_enable(struct device *device, bool enable) +#define HID_EVENT_FILTER_UUID "eeec56b3-4442-408f-a792-4edd4d758054" + +enum intel_hid_dsm_fn_codes { + INTEL_HID_DSM_FN_INVALID, + INTEL_HID_DSM_BTNL_FN, + INTEL_HID_DSM_HDMM_FN, + INTEL_HID_DSM_HDSM_FN, + INTEL_HID_DSM_HDEM_FN, + INTEL_HID_DSM_BTNS_FN, + INTEL_HID_DSM_BTNE_FN, + INTEL_HID_DSM_HEBC_V1_FN, + INTEL_HID_DSM_VGBS_FN, + INTEL_HID_DSM_HEBC_V2_FN, + INTEL_HID_DSM_FN_MAX +}; + +static const char *intel_hid_dsm_fn_to_method[INTEL_HID_DSM_FN_MAX] = { + NULL, + "BTNL", + "HDMM", + "HDSM", + "HDEM", + "BTNS", + "BTNE", + "HEBC", + "VGBS", + "HEBC" +}; + +static unsigned long long intel_hid_dsm_fn_mask; +static guid_t intel_dsm_guid; + +static bool intel_hid_execute_method(acpi_handle handle, + enum intel_hid_dsm_fn_codes fn_index, + unsigned long long arg) { + union acpi_object *obj, argv4, req; acpi_status status; + char *method_name; - status = acpi_execute_simple_method(ACPI_HANDLE(device), "HDSM", - enable); - if (ACPI_FAILURE(status)) { + if (fn_index <= INTEL_HID_DSM_FN_INVALID || + fn_index >= INTEL_HID_DSM_FN_MAX) + return false; + + method_name = (char *)intel_hid_dsm_fn_to_method[fn_index]; + + if (!(intel_hid_dsm_fn_mask & fn_index)) + goto skip_dsm_exec; + + /* All methods expects a package with one integer element */ + req.type = ACPI_TYPE_INTEGER; + req.integer.value = arg; + + argv4.type = ACPI_TYPE_PACKAGE; + argv4.package.count = 1; + argv4.package.elements = &req; + + obj = acpi_evaluate_dsm(handle, &intel_dsm_guid, 1, fn_index, &argv4); + if (obj) { + acpi_handle_debug(handle, "Exec DSM Fn code: %d[%s] success\n", + fn_index, method_name); + ACPI_FREE(obj); + return true; + } + +skip_dsm_exec: + status = acpi_execute_simple_method(handle, method_name, arg); + if (ACPI_SUCCESS(status)) + return true; + + return false; +} + +static bool intel_hid_evaluate_method(acpi_handle handle, + enum intel_hid_dsm_fn_codes fn_index, + unsigned long long *result) +{ + union acpi_object *obj; + acpi_status status; + char *method_name; + + if (fn_index <= INTEL_HID_DSM_FN_INVALID || + fn_index >= INTEL_HID_DSM_FN_MAX) + return false; + + method_name = (char *)intel_hid_dsm_fn_to_method[fn_index]; + + if (!(intel_hid_dsm_fn_mask & fn_index)) + goto skip_dsm_eval; + + obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid, + 1, fn_index, + NULL, ACPI_TYPE_INTEGER); + if (obj) { + *result = obj->integer.value; + acpi_handle_debug(handle, + "Eval DSM Fn code: %d[%s] results: 0x%llx\n", + fn_index, method_name, *result); + ACPI_FREE(obj); + return true; + } + +skip_dsm_eval: + status = acpi_evaluate_integer(handle, method_name, NULL, result); + if (ACPI_SUCCESS(status)) + return true; + + return false; +} + +static void intel_hid_init_dsm(acpi_handle handle) +{ + union acpi_object *obj; + + guid_parse(HID_EVENT_FILTER_UUID, &intel_dsm_guid); + + obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid, 1, 0, NULL, + ACPI_TYPE_BUFFER); + if (obj) { + intel_hid_dsm_fn_mask = *obj->buffer.pointer; + ACPI_FREE(obj); + } + + acpi_handle_debug(handle, "intel_hid_dsm_fn_mask = %llx\n", + intel_hid_dsm_fn_mask); +} + +static int intel_hid_set_enable(struct device *device, bool enable) +{ + acpi_handle handle = ACPI_HANDLE(device); + + /* Enable|disable features - power button is always enabled */ + if (!intel_hid_execute_method(handle, INTEL_HID_DSM_HDSM_FN, + enable)) { dev_warn(device, "failed to %sable hotkeys\n", enable ? "en" : "dis"); return -EIO; @@ -129,9 +256,8 @@ static void intel_button_array_enable(struct device *device, bool enable) } /* Enable|disable features - power button is always enabled */ - status = acpi_execute_simple_method(handle, "BTNE", - enable ? button_cap : 1); - if (ACPI_FAILURE(status)) + if (!intel_hid_execute_method(handle, INTEL_HID_DSM_BTNE_FN, + enable ? button_cap : 1)) dev_warn(device, "failed to set button capability\n"); } @@ -217,7 +343,6 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) struct platform_device *device = context; struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); unsigned long long ev_index; - acpi_status status; if (priv->wakeup_mode) { /* @@ -269,8 +394,8 @@ wakeup: return; } - status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index); - if (ACPI_FAILURE(status)) { + if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDEM_FN, + &ev_index)) { dev_warn(&device->dev, "failed to get event index\n"); return; } @@ -284,17 +409,24 @@ static bool button_array_present(struct platform_device *device) { acpi_handle handle = ACPI_HANDLE(&device->dev); unsigned long long event_cap; - acpi_status status; - bool supported = false; - status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); - if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) - supported = true; + if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V2_FN, + &event_cap)) { + /* Check presence of 5 button array or v2 power button */ + if (event_cap & 0x60000) + return true; + } + + if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V1_FN, + &event_cap)) { + if (event_cap & 0x20000) + return true; + } if (dmi_check_system(button_array_table)) - supported = true; + return true; - return supported; + return false; } static int intel_hid_probe(struct platform_device *device) @@ -305,8 +437,9 @@ static int intel_hid_probe(struct platform_device *device) acpi_status status; int err; - status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode); - if (ACPI_FAILURE(status)) { + intel_hid_init_dsm(handle); + + if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDMM_FN, &mode)) { dev_warn(&device->dev, "failed to read mode\n"); return -ENODEV; } @@ -352,13 +485,16 @@ static int intel_hid_probe(struct platform_device *device) goto err_remove_notify; if (priv->array) { + unsigned long long dummy; + intel_button_array_enable(&device->dev, true); /* Call button load method to enable HID power button */ - status = acpi_evaluate_object(handle, "BTNL", NULL, NULL); - if (ACPI_FAILURE(status)) + if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_BTNL_FN, + &dummy)) { dev_warn(&device->dev, "failed to enable HID power button\n"); + } } device_init_wakeup(&device->dev, true); diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index c13780b8dabb..06cd7e818ed5 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -17,6 +17,7 @@ /* When NOT in tablet mode, VGBS returns with the flag 0x40 */ #define TABLET_MODE_FLAG 0x40 +#define DOCK_MODE_FLAG 0x80 MODULE_LICENSE("GPL"); MODULE_AUTHOR("AceLan Kao"); @@ -38,6 +39,8 @@ static const struct key_entry intel_vbtn_keymap[] = { { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */ { KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */ + { KE_SW, 0xCA, { .sw = { SW_DOCK, 1 } } }, /* Docked */ + { KE_SW, 0xCB, { .sw = { SW_DOCK, 0 } } }, /* Undocked */ { KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */ { KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */ { KE_END }, @@ -121,6 +124,8 @@ static void detect_tablet_mode(struct platform_device *device) m = !(obj->integer.value & TABLET_MODE_FLAG); input_report_switch(priv->input_dev, SW_TABLET_MODE, m); + m = (obj->integer.value & DOCK_MODE_FLAG) ? 1 : 0; + input_report_switch(priv->input_dev, SW_DOCK, m); out: kfree(vgbs_output.pointer); } diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 014fc1634a3d..c5ece7ef08c6 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -858,10 +858,7 @@ static u16 read_mgtv(struct ips_driver *ips) static u16 read_ptv(struct ips_driver *ips) { - u16 val, slope, offset; - - slope = (ips->pta_val & PTA_SLOPE_MASK) >> PTA_SLOPE_SHIFT; - offset = ips->pta_val & PTA_OFFSET_MASK; + u16 val; val = thm_readw(THM_PTV) & PTV_MASK; diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 43bbe74743d9..2d272a3e0176 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -196,9 +196,67 @@ static const struct pmc_bit_map cnp_pfear_map[] = { {} }; +static const struct pmc_bit_map cnp_slps0_dbg0_map[] = { + {"AUDIO_D3", BIT(0)}, + {"OTG_D3", BIT(1)}, + {"XHCI_D3", BIT(2)}, + {"LPIO_D3", BIT(3)}, + {"SDX_D3", BIT(4)}, + {"SATA_D3", BIT(5)}, + {"UFS0_D3", BIT(6)}, + {"UFS1_D3", BIT(7)}, + {"EMMC_D3", BIT(8)}, + {} +}; + +static const struct pmc_bit_map cnp_slps0_dbg1_map[] = { + {"SDIO_PLL_OFF", BIT(0)}, + {"USB2_PLL_OFF", BIT(1)}, + {"AUDIO_PLL_OFF", BIT(2)}, + {"OC_PLL_OFF", BIT(3)}, + {"MAIN_PLL_OFF", BIT(4)}, + {"XOSC_OFF", BIT(5)}, + {"LPC_CLKS_GATED", BIT(6)}, + {"PCIE_CLKREQS_IDLE", BIT(7)}, + {"AUDIO_ROSC_OFF", BIT(8)}, + {"HPET_XOSC_CLK_REQ", BIT(9)}, + {"PMC_ROSC_SLOW_CLK", BIT(10)}, + {"AON2_ROSC_GATED", BIT(11)}, + {"CLKACKS_DEASSERTED", BIT(12)}, + {} +}; + +static const struct pmc_bit_map cnp_slps0_dbg2_map[] = { + {"MPHY_CORE_GATED", BIT(0)}, + {"CSME_GATED", BIT(1)}, + {"USB2_SUS_GATED", BIT(2)}, + {"DYN_FLEX_IO_IDLE", BIT(3)}, + {"GBE_NO_LINK", BIT(4)}, + {"THERM_SEN_DISABLED", BIT(5)}, + {"PCIE_LOW_POWER", BIT(6)}, + {"ISH_VNNAON_REQ_ACT", BIT(7)}, + {"ISH_VNN_REQ_ACT", BIT(8)}, + {"CNV_VNNAON_REQ_ACT", BIT(9)}, + {"CNV_VNN_REQ_ACT", BIT(10)}, + {"NPK_VNNON_REQ_ACT", BIT(11)}, + {"PMSYNC_STATE_IDLE", BIT(12)}, + {"ALST_GT_THRES", BIT(13)}, + {"PMC_ARC_PG_READY", BIT(14)}, + {} +}; + +static const struct pmc_bit_map *cnp_slps0_dbg_maps[] = { + cnp_slps0_dbg0_map, + cnp_slps0_dbg1_map, + cnp_slps0_dbg2_map, + NULL, +}; + static const struct pmc_reg_map cnp_reg_map = { .pfear_sts = cnp_pfear_map, .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, + .slps0_dbg_maps = cnp_slps0_dbg_maps, + .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET, .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, .regmap_length = CNP_PMC_MMIO_REG_LEN, .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, @@ -252,6 +310,8 @@ static int pmc_core_check_read_lock_bit(void) } #if IS_ENABLED(CONFIG_DEBUG_FS) +static bool slps0_dbg_latch; + static void pmc_core_display_map(struct seq_file *s, int index, u8 pf_reg, const struct pmc_bit_map *pf_map) { @@ -481,6 +541,57 @@ static const struct file_operations pmc_core_ltr_ignore_ops = { .release = single_release, }; +static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset) +{ + const struct pmc_reg_map *map = pmcdev->map; + u32 fd; + + mutex_lock(&pmcdev->lock); + + if (!reset && !slps0_dbg_latch) + goto out_unlock; + + fd = pmc_core_reg_read(pmcdev, map->slps0_dbg_offset); + if (reset) + fd &= ~CNP_PMC_LATCH_SLPS0_EVENTS; + else + fd |= CNP_PMC_LATCH_SLPS0_EVENTS; + pmc_core_reg_write(pmcdev, map->slps0_dbg_offset, fd); + + slps0_dbg_latch = 0; + +out_unlock: + mutex_unlock(&pmcdev->lock); +} + +static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmcdev = s->private; + const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps; + const struct pmc_bit_map *map; + int offset; + u32 data; + + pmc_core_slps0_dbg_latch(pmcdev, false); + offset = pmcdev->map->slps0_dbg_offset; + while (*maps) { + map = *maps; + data = pmc_core_reg_read(pmcdev, offset); + offset += 4; + while (map->name) { + seq_printf(s, "SLP_S0_DBG: %-32s\tState: %s\n", + map->name, + data & map->bit_mask ? + "Yes" : "No"); + ++map; + } + ++maps; + } + pmc_core_slps0_dbg_latch(pmcdev, true); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(pmc_core_slps0_dbg); + static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { debugfs_remove_recursive(pmcdev->dbgfs_dir); @@ -514,6 +625,15 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) 0444, dir, pmcdev, &pmc_core_mphy_pg_ops); + if (pmcdev->map->slps0_dbg_maps) { + debugfs_create_file("slp_s0_debug_status", 0444, + dir, pmcdev, + &pmc_core_slps0_dbg_fops); + + debugfs_create_bool("slp_s0_dbg_latch", 0644, + dir, &slps0_dbg_latch); + } + return 0; } #else diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 5fa5f97870aa..93a7e99e1f8b 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -127,12 +127,14 @@ enum ppfear_regs { #define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET 0x193C #define CNP_PMC_LTR_IGNORE_OFFSET 0x1B0C #define CNP_PMC_PM_CFG_OFFSET 0x1818 +#define CNP_PMC_SLPS0_DBG_OFFSET 0x10B4 /* Cannonlake: PGD PFET Enable Ack Status Register(s) start */ #define CNP_PMC_HOST_PPFEAR0A 0x1D90 #define CNP_PMC_MMIO_REG_LEN 0x2000 #define CNP_PPFEAR_NUM_ENTRIES 8 #define CNP_PMC_READ_DISABLE_BIT 22 +#define CNP_PMC_LATCH_SLPS0_EVENTS BIT(31) struct pmc_bit_map { const char *name; @@ -145,6 +147,7 @@ struct pmc_bit_map { * @pfear_sts: Maps name of IP block to PPFEAR* bit * @mphy_sts: Maps name of MPHY lane to MPHY status lane status bit * @pll_sts: Maps name of PLL to corresponding bit status + * @slps0_dbg_maps: Array of SLP_S0_DBG* registers containing debug info * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit * @regmap_length: Length of memory to map from PWRMBASE address to access @@ -153,6 +156,7 @@ struct pmc_bit_map { * PPFEAR * @pm_cfg_offset: PWRMBASE offset to PM_CFG register * @pm_read_disable_bit: Bit index to read PMC_READ_DISABLE + * @slps0_dbg_offset: PWRMBASE offset to SLP_S0_DEBUG_REG* * * Each PCH has unique set of register offsets and bit indexes. This structure * captures them to have a common implementation. @@ -161,6 +165,7 @@ struct pmc_reg_map { const struct pmc_bit_map *pfear_sts; const struct pmc_bit_map *mphy_sts; const struct pmc_bit_map *pll_sts; + const struct pmc_bit_map **slps0_dbg_maps; const u32 slp_s0_offset; const u32 ltr_ignore_offset; const int regmap_length; @@ -168,6 +173,7 @@ struct pmc_reg_map { const int ppfear_buckets; const u32 pm_cfg_offset; const int pm_read_disable_bit; + const u32 slps0_dbg_offset; }; /** diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c index f1afc0ebbc68..2efeab650345 100644 --- a/drivers/platform/x86/intel_punit_ipc.c +++ b/drivers/platform/x86/intel_punit_ipc.c @@ -18,6 +18,7 @@ #include <linux/bitops.h> #include <linux/device.h> #include <linux/interrupt.h> +#include <linux/io.h> #include <linux/platform_device.h> #include <asm/intel_punit_ipc.h> diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index a0fd9aa6d932..d89936c93ba0 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -47,15 +47,26 @@ /* LPC bus IO offsets */ #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 +#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 +#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 +#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d #define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET 0x20 #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 +#define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 +#define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 +#define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 +#define MLXPLAT_CPLD_LPC_REG_WP2_OFFSET 0x33 +#define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 +#define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 +#define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 +#define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a @@ -65,9 +76,23 @@ #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a +#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 +#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 +#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 +#define MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET 0xe6 +#define MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET 0xe7 +#define MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET 0xe8 +#define MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET 0xe9 +#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET 0xea +#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET 0xeb +#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET 0xec +#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xed +#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xee +#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xef #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda + #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ @@ -77,17 +102,20 @@ MLXPLAT_CPLD_LPC_PIO_OFFSET) /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ +#define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04 #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 -#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ +#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \ + MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) +#define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 -#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0 -#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 +#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) +#define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) @@ -122,12 +150,16 @@ * @pdev_mux - array of mux platform devices * @pdev_hotplug - hotplug platform devices * @pdev_led - led platform devices + * @pdev_io_regs - register access platform devices + * @pdev_fan - FAN platform devices */ struct mlxplat_priv { struct platform_device *pdev_i2c; struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; struct platform_device *pdev_hotplug; struct platform_device *pdev_led; + struct platform_device *pdev_io_regs; + struct platform_device *pdev_fan; }; /* Regions for LPC I2C controller and LPC base register space */ @@ -288,6 +320,15 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { }, }; +static struct mlxreg_core_data mlxplat_mlxcpld_default_asic_items_data[] = { + { + .label = "asic1", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { { .data = mlxplat_mlxcpld_default_psu_items_data, @@ -316,6 +357,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { .inversed = 1, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -324,6 +374,8 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { @@ -352,6 +404,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { .inversed = 0, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -454,6 +515,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { .inversed = 1, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -492,6 +562,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { .inversed = 0, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -589,6 +668,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { .inversed = 1, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -813,6 +901,278 @@ static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), }; +/* Platform register access default */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { + { + .label = "cpld1_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld2_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "reset_long_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_short_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_ref", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_main_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_sw_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_fw_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_hotswap_or_wd", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "reset_asic_thermal", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, + { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0200, + }, + { + .label = "psu2_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0200, + }, + { + .label = "pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, + { + .label = "pwr_down", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "select_iio", + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + }, + { + .label = "asic_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .bit = 1, + .mode = 0444, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = { + .data = mlxplat_mlxcpld_default_regs_io_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data), +}; + +/* Platform register access MSN21xx, MSN201x, MSN274x systems families data */ +static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = { + { + .label = "cpld1_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld2_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "reset_long_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_short_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_ref", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_sw_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_main_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_asic_thermal", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_hotswap_or_halt", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0200, + }, + { + .label = "psu2_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0200, + }, + { + .label = "pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, + { + .label = "pwr_down", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "asic_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .bit = 1, + .mode = 0444, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_msn21xx_regs_io_data = { + .data = mlxplat_mlxcpld_msn21xx_regs_io_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_regs_io_data), +}; + +/* Platform FAN default */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { + { + .label = "pwm1", + .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, + }, + { + .label = "tacho1", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho2", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho3", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho4", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho5", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho6", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho7", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho8", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho9", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho10", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho11", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho12", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, + .mask = GENMASK(7, 0), + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_fan_data = { + .data = mlxplat_mlxcpld_default_fan_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), +}; static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) { @@ -822,14 +1182,22 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; } return false; @@ -838,15 +1206,25 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: @@ -856,6 +1234,20 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; } return false; @@ -864,15 +1256,23 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: @@ -882,11 +1282,31 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; } return false; } +static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { + { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, +}; + struct mlxplat_mlxcpld_regmap_context { void __iomem *base; }; @@ -919,6 +1339,8 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config = { .writeable_reg = mlxplat_mlxcpld_writeable_reg, .readable_reg = mlxplat_mlxcpld_readable_reg, .volatile_reg = mlxplat_mlxcpld_volatile_reg, + .reg_defaults = mlxplat_mlxcpld_regmap_default, + .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_default), .reg_read = mlxplat_mlxcpld_reg_read, .reg_write = mlxplat_mlxcpld_reg_write, }; @@ -930,6 +1352,8 @@ static struct resource mlxplat_mlxcpld_resources[] = { static struct platform_device *mlxplat_dev; static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; static struct mlxreg_core_platform_data *mlxplat_led; +static struct mlxreg_core_platform_data *mlxplat_regs_io; +static struct mlxreg_core_platform_data *mlxplat_fan; static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { @@ -944,6 +1368,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; return 1; }; @@ -961,6 +1386,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; return 1; }; @@ -978,6 +1404,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; return 1; }; @@ -995,6 +1422,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_ng_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; return 1; }; @@ -1012,6 +1440,7 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_fan = &mlxplat_default_fan_data; return 1; }; @@ -1163,7 +1592,7 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) static int __init mlxplat_init(void) { struct mlxplat_priv *priv; - int i, nr, err; + int i, j, nr, err; if (!dmi_check_system(mlxplat_dmi_table)) return -ENODEV; @@ -1233,6 +1662,15 @@ static int __init mlxplat_init(void) goto fail_platform_mux_register; } + /* Set default registers. */ + for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { + err = regmap_write(mlxplat_hotplug->regmap, + mlxplat_mlxcpld_regmap_default[j].reg, + mlxplat_mlxcpld_regmap_default[j].def); + if (err) + goto fail_platform_mux_register; + } + /* Add LED driver. */ mlxplat_led->regmap = mlxplat_hotplug->regmap; priv->pdev_led = platform_device_register_resndata( @@ -1244,14 +1682,48 @@ static int __init mlxplat_init(void) goto fail_platform_hotplug_register; } + /* Add registers io access driver. */ + if (mlxplat_regs_io) { + mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; + priv->pdev_io_regs = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-io", + PLATFORM_DEVID_NONE, NULL, 0, + mlxplat_regs_io, + sizeof(*mlxplat_regs_io)); + if (IS_ERR(priv->pdev_io_regs)) { + err = PTR_ERR(priv->pdev_io_regs); + goto fail_platform_led_register; + } + } + + /* Add FAN driver. */ + if (mlxplat_fan) { + mlxplat_fan->regmap = mlxplat_hotplug->regmap; + priv->pdev_fan = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-fan", + PLATFORM_DEVID_NONE, NULL, 0, + mlxplat_fan, + sizeof(*mlxplat_fan)); + if (IS_ERR(priv->pdev_fan)) { + err = PTR_ERR(priv->pdev_fan); + goto fail_platform_io_regs_register; + } + } + /* Sync registers with hardware. */ regcache_mark_dirty(mlxplat_hotplug->regmap); err = regcache_sync(mlxplat_hotplug->regmap); if (err) - goto fail_platform_led_register; + goto fail_platform_fan_register; return 0; +fail_platform_fan_register: + if (mlxplat_fan) + platform_device_unregister(priv->pdev_fan); +fail_platform_io_regs_register: + if (mlxplat_regs_io) + platform_device_unregister(priv->pdev_io_regs); fail_platform_led_register: platform_device_unregister(priv->pdev_led); fail_platform_hotplug_register: @@ -1272,6 +1744,10 @@ static void __exit mlxplat_exit(void) struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); int i; + if (priv->pdev_fan) + platform_device_unregister(priv->pdev_fan); + if (priv->pdev_io_regs) + platform_device_unregister(priv->pdev_io_regs); platform_device_unregister(priv->pdev_led); platform_device_unregister(priv->pdev_hotplug); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cae9b0595692..fde08a997557 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -57,6 +57,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/sched.h> +#include <linux/sched/signal.h> #include <linux/kthread.h> #include <linux/freezer.h> #include <linux/delay.h> @@ -335,6 +336,7 @@ static struct { u32 second_fan:1; u32 beep_needs_two_args:1; u32 mixer_no_level_control:1; + u32 battery_force_primary:1; u32 input_device_registered:1; u32 platform_drv_registered:1; u32 platform_drv_attrs_registered:1; @@ -343,7 +345,6 @@ static struct { u32 sensors_pdev_attrs_registered:1; u32 hotkey_poll_active:1; u32 has_adaptive_kbd:1; - u32 battery:1; } tp_features; static struct { @@ -358,9 +359,9 @@ struct thinkpad_id_data { char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ - u16 bios_model; /* 1Y = 0x5931, 0 = unknown */ - u16 ec_model; - u16 bios_release; /* 1ZETK1WW = 0x314b, 0 = unknown */ + u32 bios_model; /* 1Y = 0x3159, 0 = unknown */ + u32 ec_model; + u16 bios_release; /* 1ZETK1WW = 0x4b31, 0 = unknown */ u16 ec_release; char *model_str; /* ThinkPad T43 */ @@ -444,17 +445,20 @@ do { \ /* * Quirk handling helpers * - * ThinkPad IDs and versions seen in the field so far - * are two-characters from the set [0-9A-Z], i.e. base 36. + * ThinkPad IDs and versions seen in the field so far are + * two or three characters from the set [0-9A-Z], i.e. base 36. * * We use values well outside that range as specials. */ -#define TPACPI_MATCH_ANY 0xffffU +#define TPACPI_MATCH_ANY 0xffffffffU +#define TPACPI_MATCH_ANY_VERSION 0xffffU #define TPACPI_MATCH_UNKNOWN 0U -/* TPID('1', 'Y') == 0x5931 */ -#define TPID(__c1, __c2) (((__c2) << 8) | (__c1)) +/* TPID('1', 'Y') == 0x3159 */ +#define TPID(__c1, __c2) (((__c1) << 8) | (__c2)) +#define TPID3(__c1, __c2, __c3) (((__c1) << 16) | ((__c2) << 8) | (__c3)) +#define TPVER TPID #define TPACPI_Q_IBM(__id1, __id2, __quirk) \ { .vendor = PCI_VENDOR_ID_IBM, \ @@ -468,6 +472,12 @@ do { \ .ec = TPACPI_MATCH_ANY, \ .quirks = (__quirk) } +#define TPACPI_Q_LNV3(__id1, __id2, __id3, __quirk) \ + { .vendor = PCI_VENDOR_ID_LENOVO, \ + .bios = TPID3(__id1, __id2, __id3), \ + .ec = TPACPI_MATCH_ANY, \ + .quirks = (__quirk) } + #define TPACPI_QEC_LNV(__id1, __id2, __quirk) \ { .vendor = PCI_VENDOR_ID_LENOVO, \ .bios = TPACPI_MATCH_ANY, \ @@ -476,8 +486,8 @@ do { \ struct tpacpi_quirk { unsigned int vendor; - u16 bios; - u16 ec; + u32 bios; + u32 ec; unsigned long quirks; }; @@ -1647,16 +1657,16 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) { .vendor = (__v), \ .bios = TPID(__id1, __id2), \ .ec = TPACPI_MATCH_ANY, \ - .quirks = TPACPI_MATCH_ANY << 16 \ - | (__bv1) << 8 | (__bv2) } + .quirks = TPACPI_MATCH_ANY_VERSION << 16 \ + | TPVER(__bv1, __bv2) } #define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \ __eid, __ev1, __ev2) \ { .vendor = (__v), \ .bios = TPID(__bid1, __bid2), \ .ec = __eid, \ - .quirks = (__ev1) << 24 | (__ev2) << 16 \ - | (__bv1) << 8 | (__bv2) } + .quirks = TPVER(__ev1, __ev2) << 16 \ + | TPVER(__bv1, __bv2) } #define TPV_QI0(__id1, __id2, __bv1, __bv2) \ TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2) @@ -1798,7 +1808,7 @@ static void __init tpacpi_check_outdated_fw(void) /* note that unknown versions are set to 0x0000 and we use that */ if ((bios_version > thinkpad_id.bios_release) || (ec_version > thinkpad_id.ec_release && - ec_version != TPACPI_MATCH_ANY)) { + ec_version != TPACPI_MATCH_ANY_VERSION)) { /* * The changelogs would let us track down the exact * reason, but it is just too much of a pain to track @@ -1928,7 +1938,7 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ /* first new observed key (star, favorites) is 0x1311 */ TP_ACPI_HOTKEYSCAN_STAR = 69, TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2, - TP_ACPI_HOTKEYSCAN_UNK25, + TP_ACPI_HOTKEYSCAN_CALCULATOR, TP_ACPI_HOTKEYSCAN_BLUETOOTH, TP_ACPI_HOTKEYSCAN_KEYBOARD, @@ -3449,7 +3459,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_FAVORITES, /* Favorite app, 0x311 */ KEY_RESERVED, /* Clipping tool */ - KEY_RESERVED, + KEY_CALC, /* Calculator (above numpad, P52) */ KEY_BLUETOOTH, /* Bluetooth */ KEY_KEYBOARD /* Keyboard, 0x315 */ }, @@ -9365,7 +9375,9 @@ static int tpacpi_battery_probe(int battery) { int ret = 0; - memset(&battery_info, 0, sizeof(struct tpacpi_battery_driver_data)); + memset(&battery_info.batteries[battery], 0, + sizeof(battery_info.batteries[battery])); + /* * 1) Get the current start threshold * 2) Check for support @@ -9420,7 +9432,8 @@ static int tpacpi_battery_probe(int battery) static int tpacpi_battery_get_id(const char *battery_name) { - if (strcmp(battery_name, "BAT0") == 0) + if (strcmp(battery_name, "BAT0") == 0 || + tp_features.battery_force_primary) return BAT_PRIMARY; if (strcmp(battery_name, "BAT1") == 0) return BAT_SECONDARY; @@ -9596,8 +9609,26 @@ static struct acpi_battery_hook battery_hook = { /* Subdriver init/exit */ +static const struct tpacpi_quirk battery_quirk_table[] __initconst = { + /* + * Individual addressing is broken on models that expose the + * primary battery as BAT1. + */ + TPACPI_Q_LNV('J', '7', true), /* B5400 */ + TPACPI_Q_LNV('J', 'I', true), /* Thinkpad 11e */ + TPACPI_Q_LNV3('R', '0', 'B', true), /* Thinkpad 11e gen 3 */ + TPACPI_Q_LNV3('R', '0', 'C', true), /* Thinkpad 13 */ + TPACPI_Q_LNV3('R', '0', 'J', true), /* Thinkpad 13 gen 2 */ +}; + static int __init tpacpi_battery_init(struct ibm_init_struct *ibm) { + memset(&battery_info, 0, sizeof(battery_info)); + + tp_features.battery_force_primary = tpacpi_check_quirks( + battery_quirk_table, + ARRAY_SIZE(battery_quirk_table)); + battery_hook_register(&battery_hook); return 0; } @@ -9808,36 +9839,37 @@ err_out: /* Probing */ -static bool __pure __init tpacpi_is_fw_digit(const char c) +static char __init tpacpi_parse_fw_id(const char * const s, + u32 *model, u16 *release) { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); -} + int i; + + if (!s || strlen(s) < 8) + goto invalid; + + for (i = 0; i < 8; i++) + if (!((s[i] >= '0' && s[i] <= '9') || + (s[i] >= 'A' && s[i] <= 'Z'))) + goto invalid; -static bool __pure __init tpacpi_is_valid_fw_id(const char * const s, - const char t) -{ /* * Most models: xxyTkkWW (#.##c) * Ancient 570/600 and -SL lacks (#.##c) */ - if (s && strlen(s) >= 8 && - tpacpi_is_fw_digit(s[0]) && - tpacpi_is_fw_digit(s[1]) && - s[2] == t && - (s[3] == 'T' || s[3] == 'N') && - tpacpi_is_fw_digit(s[4]) && - tpacpi_is_fw_digit(s[5])) - return true; + if (s[3] == 'T' || s[3] == 'N') { + *model = TPID(s[0], s[1]); + *release = TPVER(s[4], s[5]); + return s[2]; /* New models: xxxyTkkW (#.##c); T550 and some others */ - return s && strlen(s) >= 8 && - tpacpi_is_fw_digit(s[0]) && - tpacpi_is_fw_digit(s[1]) && - tpacpi_is_fw_digit(s[2]) && - s[3] == t && - (s[4] == 'T' || s[4] == 'N') && - tpacpi_is_fw_digit(s[5]) && - tpacpi_is_fw_digit(s[6]); + } else if (s[4] == 'T' || s[4] == 'N') { + *model = TPID3(s[0], s[1], s[2]); + *release = TPVER(s[5], s[6]); + return s[3]; + } + +invalid: + return '\0'; } /* returns 0 - probe ok, or < 0 - probe error. @@ -9849,6 +9881,7 @@ static int __must_check __init get_thinkpad_model_data( const struct dmi_device *dev = NULL; char ec_fw_string[18]; char const *s; + char t; if (!tp) return -EINVAL; @@ -9868,15 +9901,11 @@ static int __must_check __init get_thinkpad_model_data( return -ENOMEM; /* Really ancient ThinkPad 240X will fail this, which is fine */ - if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') || - tpacpi_is_valid_fw_id(tp->bios_version_str, 'C'))) + t = tpacpi_parse_fw_id(tp->bios_version_str, + &tp->bios_model, &tp->bios_release); + if (t != 'E' && t != 'C') return 0; - tp->bios_model = tp->bios_version_str[0] - | (tp->bios_version_str[1] << 8); - tp->bios_release = (tp->bios_version_str[4] << 8) - | tp->bios_version_str[5]; - /* * ThinkPad T23 or newer, A31 or newer, R50e or newer, * X32 or newer, all Z series; Some models must have an @@ -9895,12 +9924,9 @@ static int __must_check __init get_thinkpad_model_data( if (!tp->ec_version_str) return -ENOMEM; - if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) { - tp->ec_model = ec_fw_string[0] - | (ec_fw_string[1] << 8); - tp->ec_release = (ec_fw_string[4] << 8) - | ec_fw_string[5]; - } else { + t = tpacpi_parse_fw_id(ec_fw_string, + &tp->ec_model, &tp->ec_release); + if (t != 'H') { pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", ec_fw_string); pr_notice("please report this to %s\n", diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index eef76bfa5d73..e366977bda41 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -34,6 +34,7 @@ #define TOSHIBA_ACPI_VERSION "0.24" #define PROC_INTERFACE_VERSION 1 +#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -1682,7 +1683,7 @@ static const struct file_operations keys_proc_fops = { .write = keys_proc_write, }; -static int version_proc_show(struct seq_file *m, void *v) +static int __maybe_unused version_proc_show(struct seq_file *m, void *v) { seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); @@ -1836,6 +1837,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, return ret; toshiba->kbd_mode = mode; + toshiba_acpi->kbd_mode = mode; /* * Some laptop models with the second generation backlit @@ -1852,7 +1854,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, * event via genetlink. */ if (toshiba->kbd_type == 2 && - !toshiba_acpi->kbd_event_generated) + !toshiba->kbd_event_generated) schedule_work(&kbd_bl_work); } @@ -2413,16 +2415,21 @@ static const struct attribute_group toshiba_attr_group = { static void toshiba_acpi_kbd_bl_work(struct work_struct *work) { - struct acpi_device *acpi_dev = toshiba_acpi->acpi_dev; - /* Update the sysfs entries */ - if (sysfs_update_group(&acpi_dev->dev.kobj, + if (sysfs_update_group(&toshiba_acpi->acpi_dev->dev.kobj, &toshiba_attr_group)) pr_err("Unable to update sysfs entries\n"); + /* Notify LED subsystem about keyboard backlight change */ + if (toshiba_acpi->kbd_type == 2 && + toshiba_acpi->kbd_mode != SCI_KBD_MODE_AUTO) + led_classdev_notify_brightness_hw_changed(&toshiba_acpi->kbd_led, + (toshiba_acpi->kbd_mode == SCI_KBD_MODE_ON) ? + LED_FULL : LED_OFF); + /* Emulate the keyboard backlight event */ - acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, - dev_name(&acpi_dev->dev), + acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class, + dev_name(&toshiba_acpi->acpi_dev->dev), 0x92, 0); } @@ -3119,9 +3126,12 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) /* * Only register the LED if KBD illumination is supported * and the keyboard backlight operation mode is set to FN-Z + * or we detect a second gen keyboard backlight */ - if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { + if (dev->kbd_illum_supported && + (dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) { dev->kbd_led.name = "toshiba::kbd_backlight"; + dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED; dev->kbd_led.max_brightness = 1; dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; @@ -3237,11 +3247,16 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) pr_info("SATA power event received %x\n", event); break; case 0x92: /* Keyboard backlight mode changed */ - toshiba_acpi->kbd_event_generated = true; + dev->kbd_event_generated = true; /* Update sysfs entries */ if (sysfs_update_group(&acpi_dev->dev.kobj, &toshiba_attr_group)) pr_err("Unable to update sysfs entries\n"); + /* Notify LED subsystem about keyboard backlight change */ + if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO) + led_classdev_notify_brightness_hw_changed(&dev->kbd_led, + (dev->kbd_mode == SCI_KBD_MODE_ON) ? + LED_FULL : LED_OFF); break; case 0x85: /* Unknown */ case 0x8d: /* Unknown */ diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 853a7ce4601c..cb204f973491 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -1,5 +1,5 @@ /* - * Silead touchscreen driver DMI based configuration code + * Touchscreen driver DMI based configuration code * * Copyright (c) 2017 Red Hat Inc. * @@ -20,95 +20,147 @@ #include <linux/property.h> #include <linux/string.h> -struct silead_ts_dmi_data { +struct ts_dmi_data { const char *acpi_name; const struct property_entry *properties; }; -static const struct property_entry cube_iwork8_air_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), - PROPERTY_ENTRY_U32("touchscreen-size-y", 900), +/* NOTE: Please keep all entries sorted alphabetically */ + +static const struct property_entry chuwi_hi8_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), - PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), { } }; -static const struct silead_ts_dmi_data cube_iwork8_air_data = { +static const struct ts_dmi_data chuwi_hi8_data = { + .acpi_name = "MSSL0001:00", + .properties = chuwi_hi8_props, +}; + +static const struct property_entry chuwi_hi8_pro_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data chuwi_hi8_pro_data = { .acpi_name = "MSSL1680:00", - .properties = cube_iwork8_air_props, + .properties = chuwi_hi8_pro_props, }; -static const struct property_entry jumper_ezpad_mini3_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1700), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), +static const struct property_entry chuwi_vi8_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1724), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { - .acpi_name = "MSSL1680:00", - .properties = jumper_ezpad_mini3_props, +static const struct ts_dmi_data chuwi_vi8_data = { + .acpi_name = "MSSL1680:00", + .properties = chuwi_vi8_props, }; -static const struct property_entry jumper_ezpad_6_pro_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro.fw"), +static const struct property_entry chuwi_vi10_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 0), + PROPERTY_ENTRY_U32("touchscreen-min-y", 4), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1858), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-vi10.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data jumper_ezpad_6_pro_data = { +static const struct ts_dmi_data chuwi_vi10_data = { + .acpi_name = "MSSL0002:00", + .properties = chuwi_vi10_props, +}; + +static const struct property_entry connect_tablet9_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 9), + PROPERTY_ENTRY_U32("touchscreen-min-y", 8), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1664), + PROPERTY_ENTRY_U32("touchscreen-size-y", 878), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-connect-tablet9.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data connect_tablet9_data = { + .acpi_name = "MSSL1680:00", + .properties = connect_tablet9_props, +}; + +static const struct property_entry cube_iwork8_air_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), + PROPERTY_ENTRY_U32("touchscreen-size-y", 900), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data cube_iwork8_air_data = { .acpi_name = "MSSL1680:00", - .properties = jumper_ezpad_6_pro_props, + .properties = cube_iwork8_air_props, }; -static const struct property_entry dexp_ursus_7w_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 890), - PROPERTY_ENTRY_U32("touchscreen-size-y", 630), - PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"), +static const struct property_entry cube_knote_i1101_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 20), + PROPERTY_ENTRY_U32("touchscreen-min-y", 22), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1961), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1513), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-cube-knote-i1101.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data dexp_ursus_7w_data = { +static const struct ts_dmi_data cube_knote_i1101_data = { .acpi_name = "MSSL1680:00", - .properties = dexp_ursus_7w_props, + .properties = cube_knote_i1101_props, }; -static const struct property_entry surftab_twin_10_1_st10432_8_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1900), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), - PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl3670-surftab-twin-10-1-st10432-8.fw"), +static const struct property_entry dexp_ursus_7w_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 890), + PROPERTY_ENTRY_U32("touchscreen-size-y", 630), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data surftab_twin_10_1_st10432_8_data = { +static const struct ts_dmi_data dexp_ursus_7w_data = { .acpi_name = "MSSL1680:00", - .properties = surftab_twin_10_1_st10432_8_props, + .properties = dexp_ursus_7w_props, }; -static const struct property_entry surftab_wintron70_st70416_6_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 884), - PROPERTY_ENTRY_U32("touchscreen-size-y", 632), +static const struct property_entry digma_citi_e200_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), PROPERTY_ENTRY_STRING("firmware-name", - "gsl1686-surftab-wintron70-st70416-6.fw"), + "gsl1686-digma_citi_e200.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = { +static const struct ts_dmi_data digma_citi_e200_data = { .acpi_name = "MSSL1680:00", - .properties = surftab_wintron70_st70416_6_props, + .properties = digma_citi_e200_props, }; static const struct property_entry gp_electronic_t701_props[] = { @@ -121,162 +173,181 @@ static const struct property_entry gp_electronic_t701_props[] = { { } }; -static const struct silead_ts_dmi_data gp_electronic_t701_data = { +static const struct ts_dmi_data gp_electronic_t701_data = { .acpi_name = "MSSL1680:00", .properties = gp_electronic_t701_props, }; -static const struct property_entry pipo_w2s_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), - PROPERTY_ENTRY_U32("touchscreen-size-y", 880), - PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), +static const struct property_entry itworks_tw891_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1600), + PROPERTY_ENTRY_U32("touchscreen-size-y", 890), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl1680-pipo-w2s.fw"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-itworks-tw891.fw"), { } }; -static const struct silead_ts_dmi_data pipo_w2s_data = { +static const struct ts_dmi_data itworks_tw891_data = { .acpi_name = "MSSL1680:00", - .properties = pipo_w2s_props, + .properties = itworks_tw891_props, }; -static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = { - PROPERTY_ENTRY_U32("touchscreen-min-x", 32), - PROPERTY_ENTRY_U32("touchscreen-min-y", 16), - PROPERTY_ENTRY_U32("touchscreen-size-x", 1692), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1146), - PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl3680-pov-mobii-wintab-p800w-v20.fw"), +static const struct property_entry jumper_ezpad_6_pro_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v20_data = { +static const struct ts_dmi_data jumper_ezpad_6_pro_data = { .acpi_name = "MSSL1680:00", - .properties = pov_mobii_wintab_p800w_v20_props, + .properties = jumper_ezpad_6_pro_props, }; -static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1800), +static const struct property_entry jumper_ezpad_mini3_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1700), PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl3692-pov-mobii-wintab-p800w.fw"), - PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), { } }; -static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v21_data = { +static const struct ts_dmi_data jumper_ezpad_mini3_data = { .acpi_name = "MSSL1680:00", - .properties = pov_mobii_wintab_p800w_v21_props, + .properties = jumper_ezpad_mini3_props, }; -static const struct property_entry itworks_tw891_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1600), - PROPERTY_ENTRY_U32("touchscreen-size-y", 890), +static const struct property_entry onda_obook_20_plus_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-itworks-tw891.fw"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data itworks_tw891_data = { +static const struct ts_dmi_data onda_obook_20_plus_data = { .acpi_name = "MSSL1680:00", - .properties = itworks_tw891_props, + .properties = onda_obook_20_plus_props, }; -static const struct property_entry chuwi_hi8_pro_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), +static const struct property_entry onda_v820w_32g_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-onda-v820w-32g.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data chuwi_hi8_pro_data = { +static const struct ts_dmi_data onda_v820w_32g_data = { .acpi_name = "MSSL1680:00", - .properties = chuwi_hi8_pro_props, + .properties = onda_v820w_32g_props, }; -static const struct property_entry digma_citi_e200_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), - PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), +static const struct property_entry onda_v891w_v1_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 46), + PROPERTY_ENTRY_U32("touchscreen-min-y", 8), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1676), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1130), PROPERTY_ENTRY_STRING("firmware-name", - "gsl1686-digma_citi_e200.fw"), + "gsl3680-onda-v891w-v1.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data digma_citi_e200_data = { +static const struct ts_dmi_data onda_v891w_v1_data = { .acpi_name = "MSSL1680:00", - .properties = digma_citi_e200_props, + .properties = onda_v891w_v1_props, }; -static const struct property_entry onda_obook_20_plus_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), - PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), +static const struct property_entry onda_v891w_v3_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 35), + PROPERTY_ENTRY_U32("touchscreen-min-y", 15), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1625), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1135), PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), - PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3676-onda-v891w-v3.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data onda_obook_20_plus_data = { +static const struct ts_dmi_data onda_v891w_v3_data = { .acpi_name = "MSSL1680:00", - .properties = onda_obook_20_plus_props, + .properties = onda_v891w_v3_props, }; -static const struct property_entry chuwi_hi8_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), +static const struct property_entry pipo_w2s_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), + PROPERTY_ENTRY_U32("touchscreen-size-y", 880), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_BOOL("silead,home-button"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-pipo-w2s.fw"), { } }; -static const struct silead_ts_dmi_data chuwi_hi8_data = { - .acpi_name = "MSSL0001:00", - .properties = chuwi_hi8_props, +static const struct ts_dmi_data pipo_w2s_data = { + .acpi_name = "MSSL1680:00", + .properties = pipo_w2s_props, }; -static const struct property_entry chuwi_vi8_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1724), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), +static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 32), + PROPERTY_ENTRY_U32("touchscreen-min-y", 16), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1692), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1146), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3680-pov-mobii-wintab-p800w-v20.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data chuwi_vi8_data = { - .acpi_name = "MSSL1680:00", - .properties = chuwi_vi8_props, +static const struct ts_dmi_data pov_mobii_wintab_p800w_v20_data = { + .acpi_name = "MSSL1680:00", + .properties = pov_mobii_wintab_p800w_v20_props, }; -static const struct property_entry trekstor_primebook_c13_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 2624), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1920), +static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1800), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", - "gsl1680-trekstor-primebook-c13.fw"), + "gsl3692-pov-mobii-wintab-p800w.fw"), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data pov_mobii_wintab_p800w_v21_data = { + .acpi_name = "MSSL1680:00", + .properties = pov_mobii_wintab_p800w_v21_props, +}; + +static const struct property_entry teclast_x3_plus_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data trekstor_primebook_c13_data = { +static const struct ts_dmi_data teclast_x3_plus_data = { .acpi_name = "MSSL1680:00", - .properties = trekstor_primebook_c13_props, + .properties = teclast_x3_plus_props, }; static const struct property_entry teclast_x98plus2_props[] = { @@ -290,156 +361,162 @@ static const struct property_entry teclast_x98plus2_props[] = { { } }; -static const struct silead_ts_dmi_data teclast_x98plus2_data = { +static const struct ts_dmi_data teclast_x98plus2_data = { .acpi_name = "MSSL1680:00", .properties = teclast_x98plus2_props, }; -static const struct property_entry teclast_x3_plus_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), - PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"), +static const struct property_entry trekstor_primebook_c13_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 2624), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1920), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-trekstor-primebook-c13.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data teclast_x3_plus_data = { +static const struct ts_dmi_data trekstor_primebook_c13_data = { .acpi_name = "MSSL1680:00", - .properties = teclast_x3_plus_props, + .properties = trekstor_primebook_c13_props, }; -static const struct property_entry onda_v891w_v1_props[] = { - PROPERTY_ENTRY_U32("touchscreen-min-x", 46), - PROPERTY_ENTRY_U32("touchscreen-min-y", 8), - PROPERTY_ENTRY_U32("touchscreen-size-x", 1676), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1130), +static const struct property_entry trekstor_surftab_twin_10_1_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1900), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1), PROPERTY_ENTRY_STRING("firmware-name", - "gsl3680-onda-v891w-v1.fw"), + "gsl3670-surftab-twin-10-1-st10432-8.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data trekstor_surftab_twin_10_1_data = { + .acpi_name = "MSSL1680:00", + .properties = trekstor_surftab_twin_10_1_props, +}; + +static const struct property_entry trekstor_surftab_wintron70_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 884), + PROPERTY_ENTRY_U32("touchscreen-size-y", 632), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1686-surftab-wintron70-st70416-6.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data onda_v891w_v1_data = { +static const struct ts_dmi_data trekstor_surftab_wintron70_data = { .acpi_name = "MSSL1680:00", - .properties = onda_v891w_v1_props, + .properties = trekstor_surftab_wintron70_props, }; -static const struct dmi_system_id silead_ts_dmi_table[] = { +/* NOTE: Please keep this table sorted alphabetically */ +static const struct dmi_system_id touchscreen_dmi_table[] = { { - /* CUBE iwork8 Air */ - .driver_data = (void *)&cube_iwork8_air_data, + /* Chuwi Hi8 */ + .driver_data = (void *)&chuwi_hi8_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "cube"), - DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"), - DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), + DMI_MATCH(DMI_PRODUCT_NAME, "S806"), }, }, { - /* Jumper EZpad mini3 */ - .driver_data = (void *)&jumper_ezpad_mini3_data, + /* Chuwi Hi8 (H1D_S806_206) */ + .driver_data = (void *)&chuwi_hi8_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - /* jumperx.T87.KFBNEEA02 with the version-nr dropped */ - DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), + DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + DMI_MATCH(DMI_BIOS_VERSION, "H1D_S806_206"), }, }, { - /* Jumper EZpad 6 Pro */ - .driver_data = (void *)&jumper_ezpad_6_pro_data, + /* Chuwi Hi8 Pro (CWI513) */ + .driver_data = (void *)&chuwi_hi8_pro_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Jumper"), - DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"), - DMI_MATCH(DMI_BIOS_VERSION, "5.12"), - /* Above matches are too generic, add bios-date match */ - DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"), + DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), + DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"), }, }, { - /* DEXP Ursus 7W */ - .driver_data = (void *)&dexp_ursus_7w_data, + /* Chuwi Vi8 (CWI506) */ + .driver_data = (void *)&chuwi_vi8_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "7W"), + DMI_MATCH(DMI_PRODUCT_NAME, "i86"), + DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), }, }, { - /* TrekStor SurfTab twin 10.1 ST10432-8 */ - .driver_data = (void *)&surftab_twin_10_1_st10432_8_data, + /* Chuwi Vi10 (CWI505) */ + .driver_data = (void *)&chuwi_vi10_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), - DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"), + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-PF02"), + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), + DMI_MATCH(DMI_PRODUCT_NAME, "S165"), }, }, { - /* Trekstor Surftab Wintron 7.0 ST70416-6 */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* Connect Tablet 9 */ + .driver_data = (void *)&connect_tablet9_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "ST70416-6"), - /* Exact match, different versions need different fw */ - DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), + DMI_MATCH(DMI_SYS_VENDOR, "Connect"), + DMI_MATCH(DMI_PRODUCT_NAME, "Tablet 9"), }, }, { - /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* CUBE iwork8 Air */ + .driver_data = (void *)&cube_iwork8_air_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), - DMI_MATCH(DMI_PRODUCT_NAME, - "SurfTab wintron 7.0 ST70416-6"), - /* Exact match, different versions need different fw */ - DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"), + DMI_MATCH(DMI_SYS_VENDOR, "cube"), + DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), }, }, { - /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* Cube KNote i1101 */ + .driver_data = (void *)&cube_knote_i1101_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Shenzhen PLOYER"), - DMI_MATCH(DMI_PRODUCT_NAME, "MOMO7W"), - /* Exact match, different versions need different fw */ - DMI_MATCH(DMI_BIOS_VERSION, "MOMO.G.WI71C.MABMRBA02"), + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), + DMI_MATCH(DMI_BOARD_NAME, "L1W6_I1101"), + DMI_MATCH(DMI_SYS_VENDOR, "ALLDOCUBE"), + DMI_MATCH(DMI_PRODUCT_NAME, "i1101"), }, }, { - /* GP-electronic T701 */ - .driver_data = (void *)&gp_electronic_t701_data, + /* DEXP Ursus 7W */ + .driver_data = (void *)&dexp_ursus_7w_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "T701"), - DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), + DMI_MATCH(DMI_PRODUCT_NAME, "7W"), }, }, { - /* Pipo W2S */ - .driver_data = (void *)&pipo_w2s_data, + /* Digma Citi E200 */ + .driver_data = (void *)&digma_citi_e200_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PIPO"), - DMI_MATCH(DMI_PRODUCT_NAME, "W2S"), + DMI_MATCH(DMI_SYS_VENDOR, "Digma"), + DMI_MATCH(DMI_PRODUCT_NAME, "CITI E200"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), }, }, { - /* Point of View mobii wintab p800w (v2.0) */ - .driver_data = (void *)&pov_mobii_wintab_p800w_v20_data, + /* GP-electronic T701 */ + .driver_data = (void *)&gp_electronic_t701_data, .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), - DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), - DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1014"), - /* Above matches are too generic, add bios-date match */ - DMI_MATCH(DMI_BIOS_DATE, "10/24/2014"), + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "T701"), + DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), }, }, { - /* Point of View mobii wintab p800w (v2.1) */ - .driver_data = (void *)&pov_mobii_wintab_p800w_v21_data, + /* I.T.Works TW701 (same hardware as the Trekstor ST70416-6) */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), - DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), - DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), - /* Above matches are too generic, add bios-date match */ - DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "i71c"), + DMI_MATCH(DMI_BIOS_VERSION, "itWORKS.G.WI71C.JGBMRB"), }, }, { @@ -451,20 +528,23 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { - /* Chuwi Hi8 Pro */ - .driver_data = (void *)&chuwi_hi8_pro_data, + /* Jumper EZpad 6 Pro */ + .driver_data = (void *)&jumper_ezpad_6_pro_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), - DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"), + DMI_MATCH(DMI_SYS_VENDOR, "Jumper"), + DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"), + DMI_MATCH(DMI_BIOS_VERSION, "5.12"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"), }, }, { - /* Digma Citi E200 */ - .driver_data = (void *)&digma_citi_e200_data, + /* Jumper EZpad mini3 */ + .driver_data = (void *)&jumper_ezpad_mini3_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Digma"), - DMI_MATCH(DMI_PRODUCT_NAME, "CITI E200"), - DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + /* jumperx.T87.KFBNEEA02 with the version-nr dropped */ + DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), }, }, { @@ -476,45 +556,71 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { - /* Chuwi Hi8 */ - .driver_data = (void *)&chuwi_hi8_data, + /* ONDA V820w DualOS */ + .driver_data = (void *)&onda_v820w_32g_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ilife"), - DMI_MATCH(DMI_PRODUCT_NAME, "S806"), + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "V820w DualOS") }, }, { - /* Chuwi Hi8 (H1D_S806_206) */ - .driver_data = (void *)&chuwi_hi8_data, + /* ONDA V891w revision P891WBEBV1B00 aka v1 */ + .driver_data = (void *)&onda_v891w_v1_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), - DMI_MATCH(DMI_BIOS_VERSION, "H1D_S806_206"), + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONDA Tablet"), + DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V001"), + /* Exact match, different versions need different fw */ + DMI_EXACT_MATCH(DMI_BIOS_VERSION, "ONDA.W89EBBN08"), }, }, { - /* Chuwi Vi8 (CWI506) */ - .driver_data = (void *)&chuwi_vi8_data, + /* ONDA V891w Dual OS P891DCF2V1A01274 64GB */ + .driver_data = (void *)&onda_v891w_v3_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "i86"), - DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), + DMI_MATCH(DMI_PRODUCT_NAME, "ONDA Tablet"), + DMI_MATCH(DMI_BIOS_VERSION, "ONDA.D890HBBNR0A"), }, }, { - /* Trekstor Primebook C13 */ - .driver_data = (void *)&trekstor_primebook_c13_data, + /* Pipo W2S */ + .driver_data = (void *)&pipo_w2s_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), - DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), + DMI_MATCH(DMI_SYS_VENDOR, "PIPO"), + DMI_MATCH(DMI_PRODUCT_NAME, "W2S"), }, }, { - /* Teclast X98 Plus II */ - .driver_data = (void *)&teclast_x98plus2_data, + /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), - DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), + DMI_MATCH(DMI_SYS_VENDOR, "Shenzhen PLOYER"), + DMI_MATCH(DMI_PRODUCT_NAME, "MOMO7W"), + /* Exact match, different versions need different fw */ + DMI_MATCH(DMI_BIOS_VERSION, "MOMO.G.WI71C.MABMRBA02"), + }, + }, + { + /* Point of View mobii wintab p800w (v2.0) */ + .driver_data = (void *)&pov_mobii_wintab_p800w_v20_data, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1014"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "10/24/2014"), + }, + }, + { + /* Point of View mobii wintab p800w (v2.1) */ + .driver_data = (void *)&pov_mobii_wintab_p800w_v21_data, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), }, }, { @@ -527,52 +633,77 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { - /* I.T.Works TW701 */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* Teclast X98 Plus II */ + .driver_data = (void *)&teclast_x98plus2_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "i71c"), - DMI_MATCH(DMI_BIOS_VERSION, "itWORKS.G.WI71C.JGBMRB"), + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), }, }, { - /* Yours Y8W81, same case and touchscreen as Chuwi Vi8 */ - .driver_data = (void *)&chuwi_vi8_data, + /* Trekstor Primebook C13 */ + .driver_data = (void *)&trekstor_primebook_c13_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "YOURS"), - DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), + DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), }, }, { - /* ONDA V891w revision P891WBEBV1B00 aka v1 */ - .driver_data = (void *)&onda_v891w_v1_data, + /* TrekStor SurfTab twin 10.1 ST10432-8 */ + .driver_data = (void *)&trekstor_surftab_twin_10_1_data, .matches = { - DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONDA Tablet"), - DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V001"), + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"), + }, + }, + { + /* Trekstor Surftab Wintron 7.0 ST70416-6 */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "ST70416-6"), /* Exact match, different versions need different fw */ - DMI_EXACT_MATCH(DMI_BIOS_VERSION, "ONDA.W89EBBN08"), + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), + }, + }, + { + /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, + "SurfTab wintron 7.0 ST70416-6"), + /* Exact match, different versions need different fw */ + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"), + }, + }, + { + /* Yours Y8W81, same case and touchscreen as Chuwi Vi8 */ + .driver_data = (void *)&chuwi_vi8_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "YOURS"), + DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), }, }, { }, }; -static const struct silead_ts_dmi_data *silead_ts_data; +static const struct ts_dmi_data *ts_data; -static void silead_ts_dmi_add_props(struct i2c_client *client) +static void ts_dmi_add_props(struct i2c_client *client) { struct device *dev = &client->dev; int error; if (has_acpi_companion(dev) && - !strncmp(silead_ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { - error = device_add_properties(dev, silead_ts_data->properties); + !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { + error = device_add_properties(dev, ts_data->properties); if (error) dev_err(dev, "failed to add properties: %d\n", error); } } -static int silead_ts_dmi_notifier_call(struct notifier_block *nb, +static int ts_dmi_notifier_call(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; @@ -582,7 +713,7 @@ static int silead_ts_dmi_notifier_call(struct notifier_block *nb, case BUS_NOTIFY_ADD_DEVICE: client = i2c_verify_client(dev); if (client) - silead_ts_dmi_add_props(client); + ts_dmi_add_props(client); break; default: @@ -592,22 +723,22 @@ static int silead_ts_dmi_notifier_call(struct notifier_block *nb, return 0; } -static struct notifier_block silead_ts_dmi_notifier = { - .notifier_call = silead_ts_dmi_notifier_call, +static struct notifier_block ts_dmi_notifier = { + .notifier_call = ts_dmi_notifier_call, }; -static int __init silead_ts_dmi_init(void) +static int __init ts_dmi_init(void) { const struct dmi_system_id *dmi_id; int error; - dmi_id = dmi_first_match(silead_ts_dmi_table); + dmi_id = dmi_first_match(touchscreen_dmi_table); if (!dmi_id) return 0; /* Not an error */ - silead_ts_data = dmi_id->driver_data; + ts_data = dmi_id->driver_data; - error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier); + error = bus_register_notifier(&i2c_bus_type, &ts_dmi_notifier); if (error) pr_err("%s: failed to register i2c bus notifier: %d\n", __func__, error); @@ -620,4 +751,4 @@ static int __init silead_ts_dmi_init(void) * itself is ready (which happens at postcore initcall level), but before * ACPI starts enumerating devices (at subsys initcall level). */ -arch_initcall(silead_ts_dmi_init); +arch_initcall(ts_dmi_init); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 8e3d0146ff8c..04791ea5d97b 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -895,7 +895,6 @@ static int wmi_dev_probe(struct device *dev) struct wmi_driver *wdriver = container_of(dev->driver, struct wmi_driver, driver); int ret = 0; - int count; char *buf; if (ACPI_FAILURE(wmi_method_enable(wblock, 1))) @@ -917,9 +916,8 @@ static int wmi_dev_probe(struct device *dev) goto probe_failure; } - count = get_order(wblock->req_buf_size); - wblock->handler_data = (void *)__get_free_pages(GFP_KERNEL, - count); + wblock->handler_data = kmalloc(wblock->req_buf_size, + GFP_KERNEL); if (!wblock->handler_data) { ret = -ENOMEM; goto probe_failure; @@ -964,8 +962,7 @@ static int wmi_dev_remove(struct device *dev) if (wdriver->filter_callback) { misc_deregister(&wblock->char_dev); kfree(wblock->char_dev.name); - free_pages((unsigned long)wblock->handler_data, - get_order(wblock->req_buf_size)); + kfree(wblock->handler_data); } if (wdriver->remove) diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index df58fc878b3e..6533aa560aa1 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -104,6 +104,17 @@ config POWER_RESET_MSM help Power off and restart support for Qualcomm boards. +config POWER_RESET_QCOM_PON + tristate "Qualcomm power-on driver" + depends on ARCH_QCOM + depends on MFD_SPMI_PMIC + select REBOOT_MODE + help + Power On support for Qualcomm boards. + If you have a Qualcomm platform and need support for + power-on and reboot reason, Say Y. + If unsure, Say N. + config POWER_RESET_OCELOT_RESET bool "Microsemi Ocelot reset driver" depends on MSCC_OCELOT || COMPILE_TEST diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 7778c7485cf1..0aebee954ac1 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o +obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o diff --git a/drivers/power/reset/gemini-poweroff.c b/drivers/power/reset/gemini-poweroff.c index 2ac291af1265..90e35c07240a 100644 --- a/drivers/power/reset/gemini-poweroff.c +++ b/drivers/power/reset/gemini-poweroff.c @@ -130,7 +130,17 @@ static int gemini_poweroff_probe(struct platform_device *pdev) val |= GEMINI_CTRL_ENABLE; writel(val, gpw->base + GEMINI_PWC_CTRLREG); - /* Now that the state machine is active, clear the IRQ */ + /* Clear the IRQ */ + val = readl(gpw->base + GEMINI_PWC_CTRLREG); + val |= GEMINI_CTRL_IRQ_CLR; + writel(val, gpw->base + GEMINI_PWC_CTRLREG); + + /* Wait for this to clear */ + val = readl(gpw->base + GEMINI_PWC_STATREG); + while (val & 0x70U) + val = readl(gpw->base + GEMINI_PWC_STATREG); + + /* Clear the IRQ again */ val = readl(gpw->base + GEMINI_PWC_CTRLREG); val |= GEMINI_CTRL_IRQ_CLR; writel(val, gpw->base + GEMINI_PWC_CTRLREG); diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c index 6b911b6b10a6..c484584745bc 100644 --- a/drivers/power/reset/ltc2952-poweroff.c +++ b/drivers/power/reset/ltc2952-poweroff.c @@ -2,7 +2,7 @@ * LTC2952 (PowerPath) driver * * Copyright (C) 2014, Xsens Technologies BV <info@xsens.com> - * Maintainer: René Moll <linux@r-moll.nl> + * Maintainer: René Moll <linux@r-moll.nl> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -319,6 +319,6 @@ static struct platform_driver ltc2952_poweroff_driver = { module_platform_driver(ltc2952_poweroff_driver); -MODULE_AUTHOR("René Moll <rene.moll@xsens.com>"); +MODULE_AUTHOR("René Moll <rene.moll@xsens.com>"); MODULE_DESCRIPTION("LTC PowerPath power-off driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c new file mode 100644 index 000000000000..0c4caaa7e88f --- /dev/null +++ b/drivers/power/reset/qcom-pon.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-18 Linaro Limited + +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/reboot-mode.h> +#include <linux/regmap.h> + +#define PON_SOFT_RB_SPARE 0x8f + +struct pm8916_pon { + struct device *dev; + struct regmap *regmap; + u32 baseaddr; + struct reboot_mode_driver reboot_mode; +}; + +static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) +{ + struct pm8916_pon *pon = container_of + (reboot, struct pm8916_pon, reboot_mode); + int ret; + + ret = regmap_update_bits(pon->regmap, + pon->baseaddr + PON_SOFT_RB_SPARE, + 0xfc, magic << 2); + if (ret < 0) + dev_err(pon->dev, "update reboot mode bits failed\n"); + + return ret; +} + +static int pm8916_pon_probe(struct platform_device *pdev) +{ + struct pm8916_pon *pon; + int error; + + pon = devm_kzalloc(&pdev->dev, sizeof(*pon), GFP_KERNEL); + if (!pon) + return -ENOMEM; + + pon->dev = &pdev->dev; + + pon->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!pon->regmap) { + dev_err(&pdev->dev, "failed to locate regmap\n"); + return -ENODEV; + } + + error = of_property_read_u32(pdev->dev.of_node, "reg", + &pon->baseaddr); + if (error) + return error; + + pon->reboot_mode.dev = &pdev->dev; + pon->reboot_mode.write = pm8916_reboot_mode_write; + error = devm_reboot_mode_register(&pdev->dev, &pon->reboot_mode); + if (error) { + dev_err(&pdev->dev, "can't register reboot mode\n"); + return error; + } + + platform_set_drvdata(pdev, pon); + + return devm_of_platform_populate(&pdev->dev); +} + +static const struct of_device_id pm8916_pon_id_table[] = { + { .compatible = "qcom,pm8916-pon" }, + { } +}; +MODULE_DEVICE_TABLE(of, pm8916_pon_id_table); + +static struct platform_driver pm8916_pon_driver = { + .probe = pm8916_pon_probe, + .driver = { + .name = "pm8916-pon", + .of_match_table = of_match_ptr(pm8916_pon_id_table), + }, +}; +module_platform_driver(pm8916_pon_driver); + +MODULE_DESCRIPTION("pm8916 Power On driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c index 102f95a09460..e9e749f87517 100644 --- a/drivers/power/reset/vexpress-poweroff.c +++ b/drivers/power/reset/vexpress-poweroff.c @@ -35,6 +35,7 @@ static void vexpress_reset_do(struct device *dev, const char *what) } static struct device *vexpress_power_off_device; +static atomic_t vexpress_restart_nb_refcnt = ATOMIC_INIT(0); static void vexpress_power_off(void) { @@ -99,10 +100,13 @@ static int _vexpress_register_restart_handler(struct device *dev) int err; vexpress_restart_device = dev; - err = register_restart_handler(&vexpress_restart_nb); - if (err) { - dev_err(dev, "cannot register restart handler (err=%d)\n", err); - return err; + if (atomic_inc_return(&vexpress_restart_nb_refcnt) == 1) { + err = register_restart_handler(&vexpress_restart_nb); + if (err) { + dev_err(dev, "cannot register restart handler (err=%d)\n", err); + atomic_dec(&vexpress_restart_nb_refcnt); + return err; + } } device_create_file(dev, &dev_attr_active); diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c index c03e96e6a041..186901c96c01 100644 --- a/drivers/power/reset/zx-reboot.c +++ b/drivers/power/reset/zx-reboot.c @@ -51,6 +51,7 @@ static int zx_reboot_probe(struct platform_device *pdev) np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu"); pcu_base = of_iomap(np, 0); + of_node_put(np); if (!pcu_base) { iounmap(base); WARN(1, "failed to map pcu_base address"); diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 428b426842f4..ff6dab0bf0dd 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -75,6 +75,17 @@ config BATTERY_88PM860X help Say Y here to enable battery monitor for Marvell 88PM860x chip. +config CHARGER_ADP5061 + tristate "ADP5061 battery charger driver" + depends on I2C + select REGMAP_I2C + help + Say Y here to enable support for the ADP5061 standalone battery + charger. + + This driver can be built as a module. If so, the module will be + called adp5061. + config BATTERY_ACT8945A tristate "Active-semi ACT8945A charger driver" depends on MFD_ACT8945A || COMPILE_TEST @@ -92,7 +103,7 @@ config BATTERY_CPCAP config BATTERY_DS2760 tristate "DS2760 battery driver (HP iPAQ & others)" - depends on W1 && W1_SLAVE_DS2760 + depends on W1 help Say Y here to enable support for batteries with ds2760 chip. @@ -624,4 +635,14 @@ config CHARGER_RT9455 help Say Y to enable support for Richtek RT9455 battery charger. +config CHARGER_CROS_USBPD + tristate "ChromeOS EC based USBPD charger" + depends on MFD_CROS_EC + default n + help + Say Y here to enable ChromeOS EC based USBPD charger + driver. This driver gets various bits of information about + what is connected to USB PD ports from the EC and converts + that into power_supply properties. + endif # POWER_SUPPLY diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index e83aa843bcc6..a26b402c45d9 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o obj-$(CONFIG_TEST_POWER) += test_power.o obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o +obj-$(CONFIG_CHARGER_ADP5061) += adp5061.o obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o obj-$(CONFIG_BATTERY_AXP20X) += axp20x_battery.o obj-$(CONFIG_CHARGER_AXP20X) += axp20x_ac_power.o @@ -83,3 +84,4 @@ obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o +obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index d9c6c7bedd85..02356f9b5f22 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -379,15 +379,13 @@ static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr) */ static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample) { - struct timespec64 ts64; + time64_t now = ktime_get_boottime_seconds(); struct ab8500_fg_avg_cap *avg = &di->avg_cap; - getnstimeofday64(&ts64); - do { avg->sum += sample - avg->samples[avg->pos]; avg->samples[avg->pos] = sample; - avg->time_stamps[avg->pos] = ts64.tv_sec; + avg->time_stamps[avg->pos] = now; avg->pos++; if (avg->pos == NBR_AVG_SAMPLES) @@ -400,7 +398,7 @@ static int ab8500_fg_add_cap_sample(struct ab8500_fg *di, int sample) * Check the time stamp for each sample. If too old, * replace with latest sample */ - } while (ts64.tv_sec - VALID_CAPACITY_SEC > avg->time_stamps[avg->pos]); + } while (now - VALID_CAPACITY_SEC > avg->time_stamps[avg->pos]); avg->avg = avg->sum / avg->nbr_samples; @@ -439,14 +437,14 @@ static void ab8500_fg_clear_cap_samples(struct ab8500_fg *di) static void ab8500_fg_fill_cap_sample(struct ab8500_fg *di, int sample) { int i; - struct timespec64 ts64; + time64_t now; struct ab8500_fg_avg_cap *avg = &di->avg_cap; - getnstimeofday64(&ts64); + now = ktime_get_boottime_seconds(); for (i = 0; i < NBR_AVG_SAMPLES; i++) { avg->samples[i] = sample; - avg->time_stamps[i] = ts64.tv_sec; + avg->time_stamps[i] = now; } avg->pos = 0; diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c new file mode 100644 index 000000000000..939fd3d8fb1a --- /dev/null +++ b/drivers/power/supply/adp5061.c @@ -0,0 +1,745 @@ +/* + * ADP5061 I2C Programmable Linear Battery Charger + * + * Copyright 2018 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/mod_devicetable.h> +#include <linux/power_supply.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/regmap.h> + +/* ADP5061 registers definition */ +#define ADP5061_ID 0x00 +#define ADP5061_REV 0x01 +#define ADP5061_VINX_SET 0x02 +#define ADP5061_TERM_SET 0x03 +#define ADP5061_CHG_CURR 0x04 +#define ADP5061_VOLTAGE_TH 0x05 +#define ADP5061_TIMER_SET 0x06 +#define ADP5061_FUNC_SET_1 0x07 +#define ADP5061_FUNC_SET_2 0x08 +#define ADP5061_INT_EN 0x09 +#define ADP5061_INT_ACT 0x0A +#define ADP5061_CHG_STATUS_1 0x0B +#define ADP5061_CHG_STATUS_2 0x0C +#define ADP5061_FAULT 0x0D +#define ADP5061_BATTERY_SHORT 0x10 +#define ADP5061_IEND 0x11 + +/* ADP5061_VINX_SET */ +#define ADP5061_VINX_SET_ILIM_MSK GENMASK(3, 0) +#define ADP5061_VINX_SET_ILIM_MODE(x) (((x) & 0x0F) << 0) + +/* ADP5061_TERM_SET */ +#define ADP5061_TERM_SET_VTRM_MSK GENMASK(7, 2) +#define ADP5061_TERM_SET_VTRM_MODE(x) (((x) & 0x3F) << 2) +#define ADP5061_TERM_SET_CHG_VLIM_MSK GENMASK(1, 0) +#define ADP5061_TERM_SET_CHG_VLIM_MODE(x) (((x) & 0x03) << 0) + +/* ADP5061_CHG_CURR */ +#define ADP5061_CHG_CURR_ICHG_MSK GENMASK(6, 2) +#define ADP5061_CHG_CURR_ICHG_MODE(x) (((x) & 0x1F) << 2) +#define ADP5061_CHG_CURR_ITRK_DEAD_MSK GENMASK(1, 0) +#define ADP5061_CHG_CURR_ITRK_DEAD_MODE(x) (((x) & 0x03) << 0) + +/* ADP5061_VOLTAGE_TH */ +#define ADP5061_VOLTAGE_TH_DIS_RCH_MSK BIT(7) +#define ADP5061_VOLTAGE_TH_DIS_RCH_MODE(x) (((x) & 0x01) << 7) +#define ADP5061_VOLTAGE_TH_VRCH_MSK GENMASK(6, 5) +#define ADP5061_VOLTAGE_TH_VRCH_MODE(x) (((x) & 0x03) << 5) +#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK GENMASK(4, 3) +#define ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(x) (((x) & 0x03) << 3) +#define ADP5061_VOLTAGE_TH_VWEAK_MSK GENMASK(2, 0) +#define ADP5061_VOLTAGE_TH_VWEAK_MODE(x) (((x) & 0x07) << 0) + +/* ADP5061_CHG_STATUS_1 */ +#define ADP5061_CHG_STATUS_1_VIN_OV(x) (((x) >> 7) & 0x1) +#define ADP5061_CHG_STATUS_1_VIN_OK(x) (((x) >> 6) & 0x1) +#define ADP5061_CHG_STATUS_1_VIN_ILIM(x) (((x) >> 5) & 0x1) +#define ADP5061_CHG_STATUS_1_THERM_LIM(x) (((x) >> 4) & 0x1) +#define ADP5061_CHG_STATUS_1_CHDONE(x) (((x) >> 3) & 0x1) +#define ADP5061_CHG_STATUS_1_CHG_STATUS(x) (((x) >> 0) & 0x7) + +/* ADP5061_CHG_STATUS_2 */ +#define ADP5061_CHG_STATUS_2_THR_STATUS(x) (((x) >> 5) & 0x7) +#define ADP5061_CHG_STATUS_2_RCH_LIM_INFO(x) (((x) >> 3) & 0x1) +#define ADP5061_CHG_STATUS_2_BAT_STATUS(x) (((x) >> 0) & 0x7) + +/* ADP5061_IEND */ +#define ADP5061_IEND_IEND_MSK GENMASK(7, 5) +#define ADP5061_IEND_IEND_MODE(x) (((x) & 0x07) << 5) + +#define ADP5061_NO_BATTERY 0x01 +#define ADP5061_ICHG_MAX 1300 // mA + +enum adp5061_chg_status { + ADP5061_CHG_OFF, + ADP5061_CHG_TRICKLE, + ADP5061_CHG_FAST_CC, + ADP5061_CHG_FAST_CV, + ADP5061_CHG_COMPLETE, + ADP5061_CHG_LDO_MODE, + ADP5061_CHG_TIMER_EXP, + ADP5061_CHG_BAT_DET, +}; + +static const int adp5061_chg_type[4] = { + [ADP5061_CHG_OFF] = POWER_SUPPLY_CHARGE_TYPE_NONE, + [ADP5061_CHG_TRICKLE] = POWER_SUPPLY_CHARGE_TYPE_TRICKLE, + [ADP5061_CHG_FAST_CC] = POWER_SUPPLY_CHARGE_TYPE_FAST, + [ADP5061_CHG_FAST_CV] = POWER_SUPPLY_CHARGE_TYPE_FAST, +}; + +static const int adp5061_vweak_th[8] = { + 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, +}; + +static const int adp5061_prechg_current[4] = { + 5, 10, 20, 80, +}; + +static const int adp5061_vmin[4] = { + 2000, 2500, 2600, 2900, +}; + +static const int adp5061_const_chg_vmax[4] = { + 3200, 3400, 3700, 3800, +}; + +static const int adp5061_const_ichg[24] = { + 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, + 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1200, 1300, +}; + +static const int adp5061_vmax[36] = { + 3800, 3820, 3840, 3860, 3880, 3900, 3920, 3940, 3960, 3980, + 4000, 4020, 4040, 4060, 4080, 4100, 4120, 4140, 4160, 4180, + 4200, 4220, 4240, 4260, 4280, 4300, 4320, 4340, 4360, 4380, + 4400, 4420, 4440, 4460, 4480, 4500, +}; + +static const int adp5061_in_current_lim[16] = { + 100, 150, 200, 250, 300, 400, 500, 600, 700, + 800, 900, 1000, 1200, 1500, 1800, 2100, +}; + +static const int adp5061_iend[8] = { + 12500, 32500, 52500, 72500, 92500, 117500, 142500, 170000, +}; + +struct adp5061_state { + struct i2c_client *client; + struct regmap *regmap; + struct power_supply *psy; +}; + +static int adp5061_get_array_index(const int *array, u8 size, int val) +{ + int i; + + for (i = 1; i < size; i++) { + if (val < array[i]) + break; + } + + return i-1; +} + +static int adp5061_get_status(struct adp5061_state *st, + u8 *status1, u8 *status2) +{ + u8 buf[2]; + int ret; + + /* CHG_STATUS1 and CHG_STATUS2 are adjacent regs */ + ret = regmap_bulk_read(st->regmap, ADP5061_CHG_STATUS_1, + &buf[0], 2); + if (ret < 0) + return ret; + + *status1 = buf[0]; + *status2 = buf[1]; + + return ret; +} + +static int adp5061_get_input_current_limit(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int mode, ret; + + ret = regmap_read(st->regmap, ADP5061_VINX_SET, ®val); + if (ret < 0) + return ret; + + mode = ADP5061_VINX_SET_ILIM_MODE(regval); + val->intval = adp5061_in_current_lim[mode] * 1000; + + return ret; +} + +static int adp5061_set_input_current_limit(struct adp5061_state *st, int val) +{ + int index; + + /* Convert from uA to mA */ + val /= 1000; + index = adp5061_get_array_index(adp5061_in_current_lim, + ARRAY_SIZE(adp5061_in_current_lim), + val); + if (index < 0) + return index; + + return regmap_update_bits(st->regmap, ADP5061_VINX_SET, + ADP5061_VINX_SET_ILIM_MSK, + ADP5061_VINX_SET_ILIM_MODE(index)); +} + +static int adp5061_set_min_voltage(struct adp5061_state *st, int val) +{ + int index; + + /* Convert from uV to mV */ + val /= 1000; + index = adp5061_get_array_index(adp5061_vmin, + ARRAY_SIZE(adp5061_vmin), + val); + if (index < 0) + return index; + + return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, + ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK, + ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(index)); +} + +static int adp5061_get_min_voltage(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); + if (ret < 0) + return ret; + + regval = ((regval & ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK) >> 3); + val->intval = adp5061_vmin[regval] * 1000; + + return ret; +} + +static int adp5061_get_chg_volt_lim(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int mode, ret; + + ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); + if (ret < 0) + return ret; + + mode = ADP5061_TERM_SET_CHG_VLIM_MODE(regval); + val->intval = adp5061_const_chg_vmax[mode] * 1000; + + return ret; +} + +static int adp5061_get_max_voltage(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(st->regmap, ADP5061_TERM_SET, ®val); + if (ret < 0) + return ret; + + regval = ((regval & ADP5061_TERM_SET_VTRM_MSK) >> 2) - 0x0F; + if (regval >= ARRAY_SIZE(adp5061_vmax)) + regval = ARRAY_SIZE(adp5061_vmax) - 1; + + val->intval = adp5061_vmax[regval] * 1000; + + return ret; +} + +static int adp5061_set_max_voltage(struct adp5061_state *st, int val) +{ + int vmax_index; + + /* Convert from uV to mV */ + val /= 1000; + if (val > 4500) + val = 4500; + + vmax_index = adp5061_get_array_index(adp5061_vmax, + ARRAY_SIZE(adp5061_vmax), val); + if (vmax_index < 0) + return vmax_index; + + vmax_index += 0x0F; + + return regmap_update_bits(st->regmap, ADP5061_TERM_SET, + ADP5061_TERM_SET_VTRM_MSK, + ADP5061_TERM_SET_VTRM_MODE(vmax_index)); +} + +static int adp5061_set_const_chg_vmax(struct adp5061_state *st, int val) +{ + int index; + + /* Convert from uV to mV */ + val /= 1000; + index = adp5061_get_array_index(adp5061_const_chg_vmax, + ARRAY_SIZE(adp5061_const_chg_vmax), + val); + if (index < 0) + return index; + + return regmap_update_bits(st->regmap, ADP5061_TERM_SET, + ADP5061_TERM_SET_CHG_VLIM_MSK, + ADP5061_TERM_SET_CHG_VLIM_MODE(index)); +} + +static int adp5061_set_const_chg_current(struct adp5061_state *st, int val) +{ + + int index; + + /* Convert from uA to mA */ + val /= 1000; + if (val > ADP5061_ICHG_MAX) + val = ADP5061_ICHG_MAX; + + index = adp5061_get_array_index(adp5061_const_ichg, + ARRAY_SIZE(adp5061_const_ichg), + val); + if (index < 0) + return index; + + return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, + ADP5061_CHG_CURR_ICHG_MSK, + ADP5061_CHG_CURR_ICHG_MODE(index)); +} + +static int adp5061_get_const_chg_current(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); + if (ret < 0) + return ret; + + regval = ((regval & ADP5061_CHG_CURR_ICHG_MSK) >> 2); + if (regval >= ARRAY_SIZE(adp5061_const_ichg)) + regval = ARRAY_SIZE(adp5061_const_ichg) - 1; + + val->intval = adp5061_const_ichg[regval] * 1000; + + return ret; +} + +static int adp5061_get_prechg_current(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(st->regmap, ADP5061_CHG_CURR, ®val); + if (ret < 0) + return ret; + + regval &= ADP5061_CHG_CURR_ITRK_DEAD_MSK; + val->intval = adp5061_prechg_current[regval] * 1000; + + return ret; +} + +static int adp5061_set_prechg_current(struct adp5061_state *st, int val) +{ + int index; + + /* Convert from uA to mA */ + val /= 1000; + index = adp5061_get_array_index(adp5061_prechg_current, + ARRAY_SIZE(adp5061_prechg_current), + val); + if (index < 0) + return index; + + return regmap_update_bits(st->regmap, ADP5061_CHG_CURR, + ADP5061_CHG_CURR_ITRK_DEAD_MSK, + ADP5061_CHG_CURR_ITRK_DEAD_MODE(index)); +} + +static int adp5061_get_vweak_th(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, ®val); + if (ret < 0) + return ret; + + regval &= ADP5061_VOLTAGE_TH_VWEAK_MSK; + val->intval = adp5061_vweak_th[regval] * 1000; + + return ret; +} + +static int adp5061_set_vweak_th(struct adp5061_state *st, int val) +{ + int index; + + /* Convert from uV to mV */ + val /= 1000; + index = adp5061_get_array_index(adp5061_vweak_th, + ARRAY_SIZE(adp5061_vweak_th), + val); + if (index < 0) + return index; + + return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH, + ADP5061_VOLTAGE_TH_VWEAK_MSK, + ADP5061_VOLTAGE_TH_VWEAK_MODE(index)); +} + +static int adp5061_get_chg_type(struct adp5061_state *st, + union power_supply_propval *val) +{ + u8 status1, status2; + int chg_type, ret; + + ret = adp5061_get_status(st, &status1, &status2); + if (ret < 0) + return ret; + + chg_type = adp5061_chg_type[ADP5061_CHG_STATUS_1_CHG_STATUS(status1)]; + if (chg_type > ADP5061_CHG_FAST_CV) + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + else + val->intval = chg_type; + + return ret; +} + +static int adp5061_get_charger_status(struct adp5061_state *st, + union power_supply_propval *val) +{ + u8 status1, status2; + int ret; + + ret = adp5061_get_status(st, &status1, &status2); + if (ret < 0) + return ret; + + switch (ADP5061_CHG_STATUS_1_CHG_STATUS(status1)) { + case ADP5061_CHG_OFF: + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case ADP5061_CHG_TRICKLE: + case ADP5061_CHG_FAST_CC: + case ADP5061_CHG_FAST_CV: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + break; + case ADP5061_CHG_COMPLETE: + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + case ADP5061_CHG_TIMER_EXP: + /* The battery must be discharging if there is a charge fault */ + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + break; + default: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + } + + return ret; +} + +static int adp5061_get_battery_status(struct adp5061_state *st, + union power_supply_propval *val) +{ + u8 status1, status2; + int ret; + + ret = adp5061_get_status(st, &status1, &status2); + if (ret < 0) + return ret; + + switch (ADP5061_CHG_STATUS_2_BAT_STATUS(status2)) { + case 0x0: /* Battery monitor off */ + case 0x1: /* No battery */ + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; + break; + case 0x2: /* VBAT < VTRK */ + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + break; + case 0x3: /* VTRK < VBAT_SNS < VWEAK */ + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; + break; + case 0x4: /* VBAT_SNS > VWEAK */ + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; + break; + } + + return ret; +} + +static int adp5061_get_termination_current(struct adp5061_state *st, + union power_supply_propval *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(st->regmap, ADP5061_IEND, ®val); + if (ret < 0) + return ret; + + regval = (regval & ADP5061_IEND_IEND_MSK) >> 5; + val->intval = adp5061_iend[regval]; + + return ret; +} + +static int adp5061_set_termination_current(struct adp5061_state *st, int val) +{ + int index; + + index = adp5061_get_array_index(adp5061_iend, + ARRAY_SIZE(adp5061_iend), + val); + if (index < 0) + return index; + + return regmap_update_bits(st->regmap, ADP5061_IEND, + ADP5061_IEND_IEND_MSK, + ADP5061_IEND_IEND_MODE(index)); +} + +static int adp5061_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct adp5061_state *st = power_supply_get_drvdata(psy); + u8 status1, status2; + int mode, ret; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + ret = adp5061_get_status(st, &status1, &status2); + if (ret < 0) + return ret; + + mode = ADP5061_CHG_STATUS_2_BAT_STATUS(status2); + if (mode == ADP5061_NO_BATTERY) + val->intval = 0; + else + val->intval = 1; + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + return adp5061_get_chg_type(st, val); + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + /* This property is used to indicate the input current + * limit into VINx (ILIM) + */ + return adp5061_get_input_current_limit(st, val); + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + /* This property is used to indicate the termination + * voltage (VTRM) + */ + return adp5061_get_max_voltage(st, val); + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + /* + * This property is used to indicate the trickle to fast + * charge threshold (VTRK_DEAD) + */ + return adp5061_get_min_voltage(st, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + /* This property is used to indicate the charging + * voltage limit (CHG_VLIM) + */ + return adp5061_get_chg_volt_lim(st, val); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + /* + * This property is used to indicate the value of the constant + * current charge (ICHG) + */ + return adp5061_get_const_chg_current(st, val); + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + /* + * This property is used to indicate the value of the trickle + * and weak charge currents (ITRK_DEAD) + */ + return adp5061_get_prechg_current(st, val); + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + /* + * This property is used to set the VWEAK threshold + * bellow this value, weak charge mode is entered + * above this value, fast chargerge mode is entered + */ + return adp5061_get_vweak_th(st, val); + case POWER_SUPPLY_PROP_STATUS: + /* + * Indicate the charger status in relation to power + * supply status property + */ + return adp5061_get_charger_status(st, val); + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + /* + * Indicate the battery status in relation to power + * supply capacity level property + */ + return adp5061_get_battery_status(st, val); + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + /* Indicate the values of the termination current */ + return adp5061_get_termination_current(st, val); + default: + return -EINVAL; + } + + return 0; +} + +static int adp5061_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct adp5061_state *st = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return adp5061_set_input_current_limit(st, val->intval); + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + return adp5061_set_max_voltage(st, val->intval); + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + return adp5061_set_min_voltage(st, val->intval); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + return adp5061_set_const_chg_vmax(st, val->intval); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + return adp5061_set_const_chg_current(st, val->intval); + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + return adp5061_set_prechg_current(st, val->intval); + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + return adp5061_set_vweak_th(st, val->intval); + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return adp5061_set_termination_current(st, val->intval); + default: + return -EINVAL; + } + + return 0; +} + +static int adp5061_prop_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return 1; + default: + return 0; + } +} + +static enum power_supply_property adp5061_props[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, + POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, +}; + +static const struct regmap_config adp5061_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct power_supply_desc adp5061_desc = { + .name = "adp5061", + .type = POWER_SUPPLY_TYPE_USB, + .get_property = adp5061_get_property, + .set_property = adp5061_set_property, + .property_is_writeable = adp5061_prop_writeable, + .properties = adp5061_props, + .num_properties = ARRAY_SIZE(adp5061_props), +}; + +static int adp5061_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct power_supply_config psy_cfg = {}; + struct adp5061_state *st; + + st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->client = client; + st->regmap = devm_regmap_init_i2c(client, + &adp5061_regmap_config); + if (IS_ERR(st->regmap)) { + dev_err(&client->dev, "Failed to initialize register map\n"); + return -EINVAL; + } + + i2c_set_clientdata(client, st); + psy_cfg.drv_data = st; + + st->psy = devm_power_supply_register(&client->dev, + &adp5061_desc, + &psy_cfg); + + if (IS_ERR(st->psy)) { + dev_err(&client->dev, "Failed to register power supply\n"); + return PTR_ERR(st->psy); + } + + return 0; +} + +static const struct i2c_device_id adp5061_id[] = { + { "adp5061", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, adp5061_id); + +static struct i2c_driver adp5061_driver = { + .driver = { + .name = KBUILD_MODNAME, + }, + .probe = adp5061_probe, + .id_table = adp5061_id, +}; +module_i2c_driver(adp5061_driver); + +MODULE_DESCRIPTION("Analog Devices adp5061 battery charger driver"); +MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 44f70dcea61e..42001df4bd13 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -222,6 +222,7 @@ static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, case 100000: if (power->axp20x_id == AXP221_ID) return -EINVAL; + /* fall through */ case 500000: case 900000: val = (900000 - intval) / 400000; diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index 6e1bc14c3304..735658ee1c60 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -718,7 +718,7 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info) } /* Determine charge current limit */ - cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; + cc = (val & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET; info->cc = cc; diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index d44ed8e17c47..f022e1b550df 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -26,7 +26,6 @@ * http://www.ti.com/product/bq27510-g1 * http://www.ti.com/product/bq27510-g2 * http://www.ti.com/product/bq27510-g3 - * http://www.ti.com/product/bq27520-g4 * http://www.ti.com/product/bq27520-g1 * http://www.ti.com/product/bq27520-g2 * http://www.ti.com/product/bq27520-g3 @@ -40,7 +39,9 @@ * http://www.ti.com/product/bq27545-g1 * http://www.ti.com/product/bq27421-g1 * http://www.ti.com/product/bq27425-g1 + * http://www.ti.com/product/bq27426 * http://www.ti.com/product/bq27411-g1 + * http://www.ti.com/product/bq27441-g1 * http://www.ti.com/product/bq27621-g1 */ diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c new file mode 100644 index 000000000000..688a16bacfbb --- /dev/null +++ b/drivers/power/supply/cros_usbpd-charger.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Power supply driver for ChromeOS EC based USB PD Charger. + * + * Copyright (c) 2014 - 2018 Google, Inc + */ + +#include <linux/module.h> +#include <linux/mfd/cros_ec.h> +#include <linux/mfd/cros_ec_commands.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/slab.h> + +#define CHARGER_DIR_NAME "CROS_USBPD_CHARGER%d" +#define CHARGER_DIR_NAME_LENGTH sizeof(CHARGER_DIR_NAME) +#define CHARGER_CACHE_UPDATE_DELAY msecs_to_jiffies(500) +#define CHARGER_MANUFACTURER_MODEL_LENGTH 32 + +#define DRV_NAME "cros-usbpd-charger" + +struct port_data { + int port_number; + char name[CHARGER_DIR_NAME_LENGTH]; + char manufacturer[CHARGER_MANUFACTURER_MODEL_LENGTH]; + char model_name[CHARGER_MANUFACTURER_MODEL_LENGTH]; + struct power_supply *psy; + struct power_supply_desc psy_desc; + int psy_usb_type; + int psy_online; + int psy_status; + int psy_current_max; + int psy_voltage_max_design; + int psy_voltage_now; + int psy_power_max; + struct charger_data *charger; + unsigned long last_update; +}; + +struct charger_data { + struct device *dev; + struct cros_ec_dev *ec_dev; + struct cros_ec_device *ec_device; + int num_charger_ports; + int num_registered_psy; + struct port_data *ports[EC_USB_PD_MAX_PORTS]; + struct notifier_block notifier; +}; + +static enum power_supply_property cros_usbpd_charger_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_USB_TYPE +}; + +static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = { + POWER_SUPPLY_USB_TYPE_UNKNOWN, + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_DCP, + POWER_SUPPLY_USB_TYPE_CDP, + POWER_SUPPLY_USB_TYPE_C, + POWER_SUPPLY_USB_TYPE_PD, + POWER_SUPPLY_USB_TYPE_PD_DRP, + POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID +}; + +static int cros_usbpd_charger_ec_command(struct charger_data *charger, + unsigned int version, + unsigned int command, + void *outdata, + unsigned int outsize, + void *indata, + unsigned int insize) +{ + struct cros_ec_dev *ec_dev = charger->ec_dev; + struct cros_ec_command *msg; + int ret; + + msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->version = version; + msg->command = ec_dev->cmd_offset + command; + msg->outsize = outsize; + msg->insize = insize; + + if (outsize) + memcpy(msg->data, outdata, outsize); + + ret = cros_ec_cmd_xfer_status(charger->ec_device, msg); + if (ret >= 0 && insize) + memcpy(indata, msg->data, insize); + + kfree(msg); + return ret; +} + +static int cros_usbpd_charger_get_num_ports(struct charger_data *charger) +{ + struct ec_response_usb_pd_ports resp; + int ret; + + ret = cros_usbpd_charger_ec_command(charger, 0, EC_CMD_USB_PD_PORTS, + NULL, 0, &resp, sizeof(resp)); + if (ret < 0) { + dev_err(charger->dev, + "Unable to get the number or ports (err:0x%x)\n", ret); + return ret; + } + + return resp.num_ports; +} + +static int cros_usbpd_charger_get_discovery_info(struct port_data *port) +{ + struct charger_data *charger = port->charger; + struct ec_params_usb_pd_discovery_entry resp; + struct ec_params_usb_pd_info_request req; + int ret; + + req.port = port->port_number; + + ret = cros_usbpd_charger_ec_command(charger, 0, + EC_CMD_USB_PD_DISCOVERY, + &req, sizeof(req), + &resp, sizeof(resp)); + if (ret < 0) { + dev_err(charger->dev, + "Unable to query discovery info (err:0x%x)\n", ret); + return ret; + } + + dev_dbg(charger->dev, "Port %d: VID = 0x%x, PID=0x%x, PTYPE=0x%x\n", + port->port_number, resp.vid, resp.pid, resp.ptype); + + snprintf(port->manufacturer, sizeof(port->manufacturer), "%x", + resp.vid); + snprintf(port->model_name, sizeof(port->model_name), "%x", resp.pid); + + return 0; +} + +static int cros_usbpd_charger_get_power_info(struct port_data *port) +{ + struct charger_data *charger = port->charger; + struct ec_response_usb_pd_power_info resp; + struct ec_params_usb_pd_power_info req; + int last_psy_status, last_psy_usb_type; + struct device *dev = charger->dev; + int ret; + + req.port = port->port_number; + ret = cros_usbpd_charger_ec_command(charger, 0, + EC_CMD_USB_PD_POWER_INFO, + &req, sizeof(req), + &resp, sizeof(resp)); + if (ret < 0) { + dev_err(dev, "Unable to query PD power info (err:0x%x)\n", ret); + return ret; + } + + last_psy_status = port->psy_status; + last_psy_usb_type = port->psy_usb_type; + + switch (resp.role) { + case USB_PD_PORT_POWER_DISCONNECTED: + port->psy_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + port->psy_online = 0; + break; + case USB_PD_PORT_POWER_SOURCE: + port->psy_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + port->psy_online = 0; + break; + case USB_PD_PORT_POWER_SINK: + port->psy_status = POWER_SUPPLY_STATUS_CHARGING; + port->psy_online = 1; + break; + case USB_PD_PORT_POWER_SINK_NOT_CHARGING: + port->psy_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + port->psy_online = 1; + break; + default: + dev_err(dev, "Unknown role %d\n", resp.role); + break; + } + + port->psy_voltage_max_design = resp.meas.voltage_max; + port->psy_voltage_now = resp.meas.voltage_now; + port->psy_current_max = resp.meas.current_max; + port->psy_power_max = resp.max_power; + + switch (resp.type) { + case USB_CHG_TYPE_BC12_SDP: + case USB_CHG_TYPE_VBUS: + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + break; + case USB_CHG_TYPE_NONE: + /* + * For dual-role devices when we are a source, the firmware + * reports the type as NONE. Report such chargers as type + * USB_PD_DRP. + */ + if (resp.role == USB_PD_PORT_POWER_SOURCE && resp.dualrole) + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_PD_DRP; + else + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + break; + case USB_CHG_TYPE_OTHER: + case USB_CHG_TYPE_PROPRIETARY: + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID; + break; + case USB_CHG_TYPE_C: + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_C; + break; + case USB_CHG_TYPE_BC12_DCP: + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; + break; + case USB_CHG_TYPE_BC12_CDP: + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; + break; + case USB_CHG_TYPE_PD: + if (resp.dualrole) + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_PD_DRP; + else + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_PD; + break; + case USB_CHG_TYPE_UNKNOWN: + /* + * While the EC is trying to determine the type of charger that + * has been plugged in, it will report the charger type as + * unknown. Additionally since the power capabilities are + * unknown, report the max current and voltage as zero. + */ + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; + port->psy_voltage_max_design = 0; + port->psy_current_max = 0; + break; + default: + dev_err(dev, "Port %d: default case!\n", port->port_number); + port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + } + + port->psy_desc.type = POWER_SUPPLY_TYPE_USB; + + dev_dbg(dev, + "Port %d: type=%d vmax=%d vnow=%d cmax=%d clim=%d pmax=%d\n", + port->port_number, resp.type, resp.meas.voltage_max, + resp.meas.voltage_now, resp.meas.current_max, + resp.meas.current_lim, resp.max_power); + + /* + * If power supply type or status changed, explicitly call + * power_supply_changed. This results in udev event getting generated + * and allows user mode apps to react quicker instead of waiting for + * their next poll of power supply status. + */ + if (last_psy_usb_type != port->psy_usb_type || + last_psy_status != port->psy_status) + power_supply_changed(port->psy); + + return 0; +} + +static int cros_usbpd_charger_get_port_status(struct port_data *port, + bool ratelimit) +{ + int ret; + + if (ratelimit && + time_is_after_jiffies(port->last_update + + CHARGER_CACHE_UPDATE_DELAY)) + return 0; + + ret = cros_usbpd_charger_get_power_info(port); + if (ret < 0) + return ret; + + ret = cros_usbpd_charger_get_discovery_info(port); + port->last_update = jiffies; + + return ret; +} + +static void cros_usbpd_charger_power_changed(struct power_supply *psy) +{ + struct port_data *port = power_supply_get_drvdata(psy); + struct charger_data *charger = port->charger; + int i; + + for (i = 0; i < charger->num_registered_psy; i++) + cros_usbpd_charger_get_port_status(charger->ports[i], false); +} + +static int cros_usbpd_charger_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct port_data *port = power_supply_get_drvdata(psy); + struct charger_data *charger = port->charger; + struct cros_ec_device *ec_device = charger->ec_device; + struct device *dev = charger->dev; + int ret; + + /* Only refresh ec_port_status for dynamic properties */ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + /* + * If mkbp_event_supported, then we can be assured that + * the driver's state for the online property is consistent + * with the hardware. However, if we aren't event driven, + * the optimization before to skip an ec_port_status get + * and only returned cached values of the online property will + * cause a delay in detecting a cable attach until one of the + * other properties are read. + * + * Allow an ec_port_status refresh for online property check + * if we're not already online to check for plug events if + * not mkbp_event_supported. + */ + if (ec_device->mkbp_event_supported || port->psy_online) + break; + /* fall through */ + case POWER_SUPPLY_PROP_CURRENT_MAX: + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = cros_usbpd_charger_get_port_status(port, true); + if (ret < 0) { + dev_err(dev, "Failed to get port status (err:0x%x)\n", + ret); + return -EINVAL; + } + break; + default: + break; + } + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = port->psy_online; + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = port->psy_status; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = port->psy_current_max * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = port->psy_voltage_max_design * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = port->psy_voltage_now * 1000; + break; + case POWER_SUPPLY_PROP_USB_TYPE: + val->intval = port->psy_usb_type; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = port->model_name; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = port->manufacturer; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cros_usbpd_charger_ec_event(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *_notify) +{ + struct cros_ec_device *ec_device; + struct charger_data *charger; + struct device *dev; + u32 host_event; + + charger = container_of(nb, struct charger_data, notifier); + ec_device = charger->ec_device; + dev = charger->dev; + + host_event = cros_ec_get_host_event(ec_device); + if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) { + cros_usbpd_charger_power_changed(charger->ports[0]->psy); + return NOTIFY_OK; + } else { + return NOTIFY_DONE; + } +} + +static void cros_usbpd_charger_unregister_notifier(void *data) +{ + struct charger_data *charger = data; + struct cros_ec_device *ec_device = charger->ec_device; + + blocking_notifier_chain_unregister(&ec_device->event_notifier, + &charger->notifier); +} + +static int cros_usbpd_charger_probe(struct platform_device *pd) +{ + struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent); + struct cros_ec_device *ec_device = ec_dev->ec_dev; + struct power_supply_desc *psy_desc; + struct device *dev = &pd->dev; + struct charger_data *charger; + struct power_supply *psy; + struct port_data *port; + int ret = -EINVAL; + int i; + + charger = devm_kzalloc(dev, sizeof(struct charger_data), + GFP_KERNEL); + if (!charger) + return -ENOMEM; + + charger->dev = dev; + charger->ec_dev = ec_dev; + charger->ec_device = ec_device; + + platform_set_drvdata(pd, charger); + + charger->num_charger_ports = cros_usbpd_charger_get_num_ports(charger); + if (charger->num_charger_ports <= 0) { + /* + * This can happen on a system that doesn't support USB PD. + * Log a message, but no need to warn. + */ + dev_info(dev, "No charging ports found\n"); + ret = -ENODEV; + goto fail_nowarn; + } + + for (i = 0; i < charger->num_charger_ports; i++) { + struct power_supply_config psy_cfg = {}; + + port = devm_kzalloc(dev, sizeof(struct port_data), GFP_KERNEL); + if (!port) { + ret = -ENOMEM; + goto fail; + } + + port->charger = charger; + port->port_number = i; + sprintf(port->name, CHARGER_DIR_NAME, i); + + psy_desc = &port->psy_desc; + psy_desc->name = port->name; + psy_desc->type = POWER_SUPPLY_TYPE_USB; + psy_desc->get_property = cros_usbpd_charger_get_prop; + psy_desc->external_power_changed = + cros_usbpd_charger_power_changed; + psy_desc->properties = cros_usbpd_charger_props; + psy_desc->num_properties = + ARRAY_SIZE(cros_usbpd_charger_props); + psy_desc->usb_types = cros_usbpd_charger_usb_types; + psy_desc->num_usb_types = + ARRAY_SIZE(cros_usbpd_charger_usb_types); + psy_cfg.drv_data = port; + + psy = devm_power_supply_register_no_ws(dev, psy_desc, + &psy_cfg); + if (IS_ERR(psy)) { + dev_err(dev, "Failed to register power supply\n"); + continue; + } + port->psy = psy; + + charger->ports[charger->num_registered_psy++] = port; + } + + if (!charger->num_registered_psy) { + ret = -ENODEV; + dev_err(dev, "No power supplies registered\n"); + goto fail; + } + + if (ec_device->mkbp_event_supported) { + /* Get PD events from the EC */ + charger->notifier.notifier_call = cros_usbpd_charger_ec_event; + ret = blocking_notifier_chain_register( + &ec_device->event_notifier, + &charger->notifier); + if (ret < 0) { + dev_warn(dev, "failed to register notifier\n"); + } else { + ret = devm_add_action_or_reset(dev, + cros_usbpd_charger_unregister_notifier, + charger); + if (ret < 0) + goto fail; + } + } + + return 0; + +fail: + WARN(1, "%s: Failing probe (err:0x%x)\n", dev_name(dev), ret); + +fail_nowarn: + dev_info(dev, "Failing probe (err:0x%x)\n", ret); + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static int cros_usbpd_charger_resume(struct device *dev) +{ + struct charger_data *charger = dev_get_drvdata(dev); + int i; + + if (!charger) + return 0; + + for (i = 0; i < charger->num_registered_psy; i++) { + power_supply_changed(charger->ports[i]->psy); + charger->ports[i]->last_update = + jiffies - CHARGER_CACHE_UPDATE_DELAY; + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(cros_usbpd_charger_pm_ops, NULL, + cros_usbpd_charger_resume); + +static struct platform_driver cros_usbpd_charger_driver = { + .driver = { + .name = DRV_NAME, + .pm = &cros_usbpd_charger_pm_ops, + }, + .probe = cros_usbpd_charger_probe +}; + +module_platform_driver(cros_usbpd_charger_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS EC USBPD charger"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/power/supply/ds2760_battery.c b/drivers/power/supply/ds2760_battery.c index ae180dc929c9..11bed88a89fa 100644 --- a/drivers/power/supply/ds2760_battery.c +++ b/drivers/power/supply/ds2760_battery.c @@ -27,9 +27,64 @@ #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/power_supply.h> - +#include <linux/suspend.h> #include <linux/w1.h> -#include "../../w1/slaves/w1_ds2760.h" +#include <linux/of.h> + +static unsigned int cache_time = 1000; +module_param(cache_time, uint, 0644); +MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); + +static bool pmod_enabled; +module_param(pmod_enabled, bool, 0644); +MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); + +static unsigned int rated_capacity; +module_param(rated_capacity, uint, 0644); +MODULE_PARM_DESC(rated_capacity, "rated battery capacity, 10*mAh or index"); + +static unsigned int current_accum; +module_param(current_accum, uint, 0644); +MODULE_PARM_DESC(current_accum, "current accumulator value"); + +#define W1_FAMILY_DS2760 0x30 + +/* Known commands to the DS2760 chip */ +#define W1_DS2760_SWAP 0xAA +#define W1_DS2760_READ_DATA 0x69 +#define W1_DS2760_WRITE_DATA 0x6C +#define W1_DS2760_COPY_DATA 0x48 +#define W1_DS2760_RECALL_DATA 0xB8 +#define W1_DS2760_LOCK 0x6A + +/* Number of valid register addresses */ +#define DS2760_DATA_SIZE 0x40 + +#define DS2760_PROTECTION_REG 0x00 + +#define DS2760_STATUS_REG 0x01 +#define DS2760_STATUS_IE (1 << 2) +#define DS2760_STATUS_SWEN (1 << 3) +#define DS2760_STATUS_RNAOP (1 << 4) +#define DS2760_STATUS_PMOD (1 << 5) + +#define DS2760_EEPROM_REG 0x07 +#define DS2760_SPECIAL_FEATURE_REG 0x08 +#define DS2760_VOLTAGE_MSB 0x0c +#define DS2760_VOLTAGE_LSB 0x0d +#define DS2760_CURRENT_MSB 0x0e +#define DS2760_CURRENT_LSB 0x0f +#define DS2760_CURRENT_ACCUM_MSB 0x10 +#define DS2760_CURRENT_ACCUM_LSB 0x11 +#define DS2760_TEMP_MSB 0x18 +#define DS2760_TEMP_LSB 0x19 +#define DS2760_EEPROM_BLOCK0 0x20 +#define DS2760_ACTIVE_FULL 0x20 +#define DS2760_EEPROM_BLOCK1 0x30 +#define DS2760_STATUS_WRITE_REG 0x31 +#define DS2760_RATED_CAPACITY 0x32 +#define DS2760_CURRENT_OFFSET_BIAS 0x33 +#define DS2760_ACTIVE_EMPTY 0x3b struct ds2760_device_info { struct device *dev; @@ -55,28 +110,113 @@ struct ds2760_device_info { int full_counter; struct power_supply *bat; struct power_supply_desc bat_desc; - struct device *w1_dev; struct workqueue_struct *monitor_wqueue; struct delayed_work monitor_work; struct delayed_work set_charged_work; + struct notifier_block pm_notifier; }; -static unsigned int cache_time = 1000; -module_param(cache_time, uint, 0644); -MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); +static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count, + int io) +{ + struct w1_slave *sl = container_of(dev, struct w1_slave, dev); -static bool pmod_enabled; -module_param(pmod_enabled, bool, 0644); -MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); + if (!dev) + return 0; -static unsigned int rated_capacity; -module_param(rated_capacity, uint, 0644); -MODULE_PARM_DESC(rated_capacity, "rated battery capacity, 10*mAh or index"); + mutex_lock(&sl->master->bus_mutex); -static unsigned int current_accum; -module_param(current_accum, uint, 0644); -MODULE_PARM_DESC(current_accum, "current accumulator value"); + if (addr > DS2760_DATA_SIZE || addr < 0) { + count = 0; + goto out; + } + if (addr + count > DS2760_DATA_SIZE) + count = DS2760_DATA_SIZE - addr; + + if (!w1_reset_select_slave(sl)) { + if (!io) { + w1_write_8(sl->master, W1_DS2760_READ_DATA); + w1_write_8(sl->master, addr); + count = w1_read_block(sl->master, buf, count); + } else { + w1_write_8(sl->master, W1_DS2760_WRITE_DATA); + w1_write_8(sl->master, addr); + w1_write_block(sl->master, buf, count); + /* XXX w1_write_block returns void, not n_written */ + } + } + +out: + mutex_unlock(&sl->master->bus_mutex); + + return count; +} + +static int w1_ds2760_read(struct device *dev, + char *buf, int addr, + size_t count) +{ + return w1_ds2760_io(dev, buf, addr, count, 0); +} + +static int w1_ds2760_write(struct device *dev, + char *buf, + int addr, size_t count) +{ + return w1_ds2760_io(dev, buf, addr, count, 1); +} + +static int w1_ds2760_eeprom_cmd(struct device *dev, int addr, int cmd) +{ + struct w1_slave *sl = container_of(dev, struct w1_slave, dev); + + if (!dev) + return -EINVAL; + + mutex_lock(&sl->master->bus_mutex); + + if (w1_reset_select_slave(sl) == 0) { + w1_write_8(sl->master, cmd); + w1_write_8(sl->master, addr); + } + + mutex_unlock(&sl->master->bus_mutex); + return 0; +} + +static int w1_ds2760_store_eeprom(struct device *dev, int addr) +{ + return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_COPY_DATA); +} + +static int w1_ds2760_recall_eeprom(struct device *dev, int addr) +{ + return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA); +} + +static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + return w1_ds2760_read(dev, buf, off, count); +} + +static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE); + +static struct bin_attribute *w1_ds2760_bin_attrs[] = { + &bin_attr_w1_slave, + NULL, +}; + +static const struct attribute_group w1_ds2760_group = { + .bin_attrs = w1_ds2760_bin_attrs, +}; +static const struct attribute_group *w1_ds2760_groups[] = { + &w1_ds2760_group, + NULL, +}; /* Some batteries have their rated capacity stored a N * 10 mAh, while * others use an index into this table. */ static int rated_capacities[] = { @@ -138,10 +278,10 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di) count = DS2760_TEMP_LSB - start + 1; } - ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count); + ret = w1_ds2760_read(di->dev, di->raw + start, start, count); if (ret != count) { dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n", - di->w1_dev); + di->dev); return 1; } @@ -242,7 +382,7 @@ static void ds2760_battery_set_current_accum(struct ds2760_device_info *di, acr[0] = acr_val >> 8; acr[1] = acr_val & 0xff; - if (w1_ds2760_write(di->w1_dev, acr, DS2760_CURRENT_ACCUM_MSB, 2) < 2) + if (w1_ds2760_write(di->dev, acr, DS2760_CURRENT_ACCUM_MSB, 2) < 2) dev_warn(di->dev, "ACR write failed\n"); } @@ -297,9 +437,9 @@ static void ds2760_battery_write_status(struct ds2760_device_info *di, if (status == di->raw[DS2760_STATUS_REG]) return; - w1_ds2760_write(di->w1_dev, &status, DS2760_STATUS_WRITE_REG, 1); - w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); - w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); + w1_ds2760_write(di->dev, &status, DS2760_STATUS_WRITE_REG, 1); + w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK1); + w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK1); } static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di, @@ -308,9 +448,9 @@ static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di, if (rated_capacity == di->raw[DS2760_RATED_CAPACITY]) return; - w1_ds2760_write(di->w1_dev, &rated_capacity, DS2760_RATED_CAPACITY, 1); - w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); - w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); + w1_ds2760_write(di->dev, &rated_capacity, DS2760_RATED_CAPACITY, 1); + w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK1); + w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK1); } static void ds2760_battery_write_active_full(struct ds2760_device_info *di, @@ -325,9 +465,9 @@ static void ds2760_battery_write_active_full(struct ds2760_device_info *di, tmp[1] == di->raw[DS2760_ACTIVE_FULL + 1]) return; - w1_ds2760_write(di->w1_dev, tmp, DS2760_ACTIVE_FULL, sizeof(tmp)); - w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0); - w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0); + w1_ds2760_write(di->dev, tmp, DS2760_ACTIVE_FULL, sizeof(tmp)); + w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK0); + w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK0); /* Write to the di->raw[] buffer directly - the DS2760_ACTIVE_FULL * values won't be read back by ds2760_battery_read_status() */ @@ -383,9 +523,9 @@ static void ds2760_battery_set_charged_work(struct work_struct *work) dev_dbg(di->dev, "%s: bias = %d\n", __func__, bias); - w1_ds2760_write(di->w1_dev, &bias, DS2760_CURRENT_OFFSET_BIAS, 1); - w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); - w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); + w1_ds2760_write(di->dev, &bias, DS2760_CURRENT_OFFSET_BIAS, 1); + w1_ds2760_store_eeprom(di->dev, DS2760_EEPROM_BLOCK1); + w1_ds2760_recall_eeprom(di->dev, DS2760_EEPROM_BLOCK1); /* Write to the di->raw[] buffer directly - the CURRENT_OFFSET_BIAS * value won't be read back by ds2760_battery_read_status() */ @@ -504,24 +644,55 @@ static enum power_supply_property ds2760_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY, }; -static int ds2760_battery_probe(struct platform_device *pdev) +static int ds2760_pm_notifier(struct notifier_block *notifier, + unsigned long pm_event, + void *unused) +{ + struct ds2760_device_info *di = + container_of(notifier, struct ds2760_device_info, pm_notifier); + + switch (pm_event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; + break; + + case PM_POST_RESTORE: + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; + power_supply_changed(di->bat); + mod_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); + + break; + + case PM_RESTORE_PREPARE: + default: + break; + } + + return NOTIFY_DONE; +} + +static int w1_ds2760_add_slave(struct w1_slave *sl) { struct power_supply_config psy_cfg = {}; - char status; - int retval = 0; struct ds2760_device_info *di; + struct device *dev = &sl->dev; + int retval = 0; + char name[32]; + char status; - di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); + di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); if (!di) { retval = -ENOMEM; goto di_alloc_failed; } - platform_set_drvdata(pdev, di); + snprintf(name, sizeof(name), "ds2760-battery.%d", dev->id); - di->dev = &pdev->dev; - di->w1_dev = pdev->dev.parent; - di->bat_desc.name = dev_name(&pdev->dev); + di->dev = dev; + di->bat_desc.name = name; di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; di->bat_desc.properties = ds2760_battery_props; di->bat_desc.num_properties = ARRAY_SIZE(ds2760_battery_props); @@ -533,10 +704,30 @@ static int ds2760_battery_probe(struct platform_device *pdev) di->bat_desc.external_power_changed = ds2760_battery_external_power_changed; - psy_cfg.drv_data = di; + psy_cfg.drv_data = di; + + if (dev->of_node) { + u32 tmp; + + psy_cfg.of_node = dev->of_node; + + if (!of_property_read_bool(dev->of_node, "maxim,pmod-enabled")) + pmod_enabled = true; + + if (!of_property_read_u32(dev->of_node, + "maxim,cache-time-ms", &tmp)) + cache_time = tmp; + + if (!of_property_read_u32(dev->of_node, + "rated-capacity-microamp-hours", + &tmp)) + rated_capacity = tmp / 10; /* property is in mAh */ + } di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; + sl->family_data = di; + /* enable sleep mode feature */ ds2760_battery_read_status(di); status = di->raw[DS2760_STATUS_REG]; @@ -547,7 +738,7 @@ static int ds2760_battery_probe(struct platform_device *pdev) ds2760_battery_write_status(di, status); - /* set rated capacity from module param */ + /* set rated capacity from module param or device tree */ if (rated_capacity) ds2760_battery_write_rated_capacity(di, rated_capacity); @@ -556,7 +747,7 @@ static int ds2760_battery_probe(struct platform_device *pdev) if (current_accum) ds2760_battery_set_current_accum(di, current_accum); - di->bat = power_supply_register(&pdev->dev, &di->bat_desc, &psy_cfg); + di->bat = power_supply_register(dev, &di->bat_desc, &psy_cfg); if (IS_ERR(di->bat)) { dev_err(di->dev, "failed to register battery\n"); retval = PTR_ERR(di->bat); @@ -566,14 +757,16 @@ static int ds2760_battery_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); INIT_DELAYED_WORK(&di->set_charged_work, ds2760_battery_set_charged_work); - di->monitor_wqueue = alloc_ordered_workqueue(dev_name(&pdev->dev), - WQ_MEM_RECLAIM); + di->monitor_wqueue = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); if (!di->monitor_wqueue) { retval = -ESRCH; goto workqueue_failed; } queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); + di->pm_notifier.notifier_call = ds2760_pm_notifier; + register_pm_notifier(&di->pm_notifier); + goto success; workqueue_failed: @@ -584,65 +777,40 @@ success: return retval; } -static int ds2760_battery_remove(struct platform_device *pdev) +static void w1_ds2760_remove_slave(struct w1_slave *sl) { - struct ds2760_device_info *di = platform_get_drvdata(pdev); + struct ds2760_device_info *di = sl->family_data; + unregister_pm_notifier(&di->pm_notifier); cancel_delayed_work_sync(&di->monitor_work); cancel_delayed_work_sync(&di->set_charged_work); destroy_workqueue(di->monitor_wqueue); power_supply_unregister(di->bat); - - return 0; -} - -#ifdef CONFIG_PM - -static int ds2760_battery_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct ds2760_device_info *di = platform_get_drvdata(pdev); - - di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; - - return 0; -} - -static int ds2760_battery_resume(struct platform_device *pdev) -{ - struct ds2760_device_info *di = platform_get_drvdata(pdev); - - di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; - power_supply_changed(di->bat); - - mod_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); - - return 0; } -#else - -#define ds2760_battery_suspend NULL -#define ds2760_battery_resume NULL - -#endif /* CONFIG_PM */ - -MODULE_ALIAS("platform:ds2760-battery"); +#ifdef CONFIG_OF +static const struct of_device_id w1_ds2760_of_ids[] = { + { .compatible = "maxim,ds2760" }, + {} +}; +#endif -static struct platform_driver ds2760_battery_driver = { - .driver = { - .name = "ds2760-battery", - }, - .probe = ds2760_battery_probe, - .remove = ds2760_battery_remove, - .suspend = ds2760_battery_suspend, - .resume = ds2760_battery_resume, +static struct w1_family_ops w1_ds2760_fops = { + .add_slave = w1_ds2760_add_slave, + .remove_slave = w1_ds2760_remove_slave, + .groups = w1_ds2760_groups, }; -module_platform_driver(ds2760_battery_driver); +static struct w1_family w1_ds2760_family = { + .fid = W1_FAMILY_DS2760, + .fops = &w1_ds2760_fops, + .of_match_table = of_match_ptr(w1_ds2760_of_ids), +}; +module_w1_family(w1_ds2760_family); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " "Matt Reimer <mreimer@vpop.net>, " "Anton Vorontsov <cbou@mail.ru>"); -MODULE_DESCRIPTION("ds2760 battery driver"); +MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2760)); diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c index 28dc056eaafa..bc462d1ec963 100644 --- a/drivers/power/supply/generic-adc-battery.c +++ b/drivers/power/supply/generic-adc-battery.c @@ -241,10 +241,10 @@ static int gab_probe(struct platform_device *pdev) struct power_supply_desc *psy_desc; struct power_supply_config psy_cfg = {}; struct gab_platform_data *pdata = pdev->dev.platform_data; - enum power_supply_property *properties; int ret = 0; int chan; - int index = 0; + int index = ARRAY_SIZE(gab_props); + bool any = false; adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); if (!adc_bat) { @@ -278,8 +278,6 @@ static int gab_probe(struct platform_device *pdev) } memcpy(psy_desc->properties, gab_props, sizeof(gab_props)); - properties = (enum power_supply_property *) - ((char *)psy_desc->properties + sizeof(gab_props)); /* * getting channel from iio and copying the battery properties @@ -293,15 +291,22 @@ static int gab_probe(struct platform_device *pdev) adc_bat->channel[chan] = NULL; } else { /* copying properties for supported channels only */ - memcpy(properties + sizeof(*(psy_desc->properties)) * index, - &gab_dyn_props[chan], - sizeof(gab_dyn_props[chan])); - index++; + int index2; + + for (index2 = 0; index2 < index; index2++) { + if (psy_desc->properties[index2] == + gab_dyn_props[chan]) + break; /* already known */ + } + if (index2 == index) /* really new */ + psy_desc->properties[index++] = + gab_dyn_props[chan]; + any = true; } } /* none of the channels are supported so let's bail out */ - if (index == 0) { + if (!any) { ret = -ENODEV; goto second_mem_fail; } @@ -312,7 +317,7 @@ static int gab_probe(struct platform_device *pdev) * as come channels may be not be supported by the device.So * we need to take care of that. */ - psy_desc->num_properties = ARRAY_SIZE(gab_props) + index; + psy_desc->num_properties = index; adc_bat->psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg); if (IS_ERR(adc_bat->psy)) { diff --git a/drivers/power/supply/lego_ev3_battery.c b/drivers/power/supply/lego_ev3_battery.c index 7b993d669f7f..1ae3710909b7 100644 --- a/drivers/power/supply/lego_ev3_battery.c +++ b/drivers/power/supply/lego_ev3_battery.c @@ -39,7 +39,7 @@ static int lego_ev3_battery_get_property(struct power_supply *psy, union power_supply_propval *val) { struct lego_ev3_battery *batt = power_supply_get_drvdata(psy); - int val2; + int ret, val2; switch (psp) { case POWER_SUPPLY_PROP_TECHNOLOGY: @@ -47,11 +47,18 @@ static int lego_ev3_battery_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* battery voltage is iio channel * 2 + Vce of transistor */ - iio_read_channel_processed(batt->iio_v, &val->intval); + ret = iio_read_channel_processed(batt->iio_v, &val->intval); + if (ret) + return ret; + val->intval *= 2000; - val->intval += 200000; + val->intval += 50000; + /* plus adjust for shunt resistor drop */ - iio_read_channel_processed(batt->iio_i, &val2); + ret = iio_read_channel_processed(batt->iio_i, &val2); + if (ret) + return ret; + val2 *= 1000; val2 /= 15; val->intval += val2; @@ -64,7 +71,10 @@ static int lego_ev3_battery_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CURRENT_NOW: /* battery current is iio channel / 15 / 0.05 ohms */ - iio_read_channel_processed(batt->iio_i, &val->intval); + ret = iio_read_channel_processed(batt->iio_i, &val->intval); + if (ret) + return ret; + val->intval *= 20000; val->intval /= 15; break; diff --git a/drivers/power/supply/max1721x_battery.c b/drivers/power/supply/max1721x_battery.c index 9ee601a03d9b..9ca895b0dabb 100644 --- a/drivers/power/supply/max1721x_battery.c +++ b/drivers/power/supply/max1721x_battery.c @@ -372,7 +372,7 @@ static int devm_w1_max1721x_add_device(struct w1_slave *sl) } if (!info->rsense) { - dev_warn(info->w1_dev, "RSenese not calibrated, set 10 mOhms!\n"); + dev_warn(info->w1_dev, "RSense not calibrated, set 10 mOhms!\n"); info->rsense = 1000; /* in regs in 10^-5 */ } dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100); diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c index 6c78884bad5e..749c7926e3c9 100644 --- a/drivers/power/supply/max77693_charger.c +++ b/drivers/power/supply/max77693_charger.c @@ -567,6 +567,7 @@ static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg case 4800000: case 4900000: data = (uvolt - 4700000) / 100000; + break; default: dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n"); return -EINVAL; diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index d21f478741c1..e85361878450 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/notifier.h> #include <linux/err.h> @@ -140,8 +141,13 @@ static void power_supply_deferred_register_work(struct work_struct *work) struct power_supply *psy = container_of(work, struct power_supply, deferred_register_work.work); - if (psy->dev.parent) - mutex_lock(&psy->dev.parent->mutex); + if (psy->dev.parent) { + while (!mutex_trylock(&psy->dev.parent->mutex)) { + if (psy->removing) + return; + msleep(10); + } + } power_supply_changed(psy); @@ -1082,6 +1088,7 @@ EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws); void power_supply_unregister(struct power_supply *psy) { WARN_ON(atomic_dec_return(&psy->use_cnt)); + psy->removing = true; cancel_work_sync(&psy->changed_work); cancel_delayed_work_sync(&psy->deferred_register_work); sysfs_remove_link(&psy->dev.kobj, "powers"); diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 83d7b4115857..8ba6abf584de 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/power/sbs-battery.h> #include <linux/power_supply.h> #include <linux/slab.h> @@ -156,6 +157,9 @@ static enum power_supply_property sbs_properties[] = { POWER_SUPPLY_PROP_MODEL_NAME }; +/* Supports special manufacturer commands from TI BQ20Z75 IC. */ +#define SBS_FLAGS_TI_BQ20Z75 BIT(0) + struct sbs_info { struct i2c_client *client; struct power_supply *power_supply; @@ -168,6 +172,7 @@ struct sbs_info { u32 poll_retry_count; struct delayed_work work; struct mutex mode_lock; + u32 flags; }; static char model_name[I2C_SMBUS_BLOCK_MAX + 1]; @@ -316,16 +321,40 @@ static int sbs_get_battery_presence_and_health( struct i2c_client *client, enum power_supply_property psp, union power_supply_propval *val) { + int ret; + + if (psp == POWER_SUPPLY_PROP_PRESENT) { + /* Dummy command; if it succeeds, battery is present. */ + ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr); + if (ret < 0) + val->intval = 0; /* battery disconnected */ + else + val->intval = 1; /* battery present */ + } else { /* POWER_SUPPLY_PROP_HEALTH */ + /* SBS spec doesn't have a general health command. */ + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; + } + + return 0; +} + +static int sbs_get_ti_battery_presence_and_health( + struct i2c_client *client, enum power_supply_property psp, + union power_supply_propval *val) +{ s32 ret; /* * Write to ManufacturerAccess with ManufacturerAccess command - * and then read the status. Do not check for error on the write - * since not all batteries implement write access to this command, - * while others mandate it. + * and then read the status. */ - sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, - MANUFACTURER_ACCESS_STATUS); + ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, + MANUFACTURER_ACCESS_STATUS); + if (ret < 0) { + if (psp == POWER_SUPPLY_PROP_PRESENT) + val->intval = 0; /* battery removed */ + return ret; + } ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr); if (ret < 0) { @@ -600,7 +629,12 @@ static int sbs_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_HEALTH: - ret = sbs_get_battery_presence_and_health(client, psp, val); + if (client->flags & SBS_FLAGS_TI_BQ20Z75) + ret = sbs_get_ti_battery_presence_and_health(client, + psp, val); + else + ret = sbs_get_battery_presence_and_health(client, psp, + val); if (psp == POWER_SUPPLY_PROP_PRESENT) return 0; break; @@ -806,6 +840,7 @@ static int sbs_probe(struct i2c_client *client, if (!chip) return -ENOMEM; + chip->flags = (u32)(uintptr_t)of_device_get_match_data(&client->dev); chip->client = client; chip->enable_detection = false; psy_cfg.of_node = client->dev.of_node; @@ -911,16 +946,19 @@ static int sbs_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct sbs_info *chip = i2c_get_clientdata(client); + int ret; if (chip->poll_time > 0) cancel_delayed_work_sync(&chip->work); - /* - * Write to manufacturer access with sleep command. - * Support is manufacturer dependend, so ignore errors. - */ - sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, - MANUFACTURER_ACCESS_SLEEP); + if (chip->flags & SBS_FLAGS_TI_BQ20Z75) { + /* Write to manufacturer access with sleep command. */ + ret = sbs_write_word_data(client, + sbs_data[REG_MANUFACTURER_DATA].addr, + MANUFACTURER_ACCESS_SLEEP); + if (chip->is_present && ret < 0) + return ret; + } return 0; } @@ -941,7 +979,10 @@ MODULE_DEVICE_TABLE(i2c, sbs_id); static const struct of_device_id sbs_dt_ids[] = { { .compatible = "sbs,sbs-battery" }, - { .compatible = "ti,bq20z75" }, + { + .compatible = "ti,bq20z75", + .data = (void *)SBS_FLAGS_TI_BQ20Z75, + }, { } }; MODULE_DEVICE_TABLE(of, sbs_dt_ids); diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c index 1f5234098aaf..814c2b81fdfe 100644 --- a/drivers/power/supply/tps65217_charger.c +++ b/drivers/power/supply/tps65217_charger.c @@ -1,20 +1,8 @@ -/* - * Battery charger driver for TI's tps65217 - * - * Copyright (c) 2015, Collabora Ltd. - - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ +// SPDX-License-Identifier: GPL-2.0 +// Battery charger driver for TI's tps65217 +// +// Copyright (C) 2015 Collabora Ltd. +// Author: Enric Balletbo i Serra <enric.balletbo@collabora.com> /* * Battery charger driver for TI's tps65217 diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index a2740cf57ad3..15c0ca15e2aa 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -230,7 +230,8 @@ static irqreturn_t wm8350_charger_handler(int irq, void *data) case WM8350_IRQ_EXT_USB_FB: case WM8350_IRQ_EXT_WALL_FB: wm8350_charger_config(wm8350, policy); - case WM8350_IRQ_EXT_BAT_FB: /* Fall through */ + /* Fall through */ + case WM8350_IRQ_EXT_BAT_FB: power_supply_changed(power->battery); power_supply_changed(power->usb); power_supply_changed(power->ac); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index a4d262db9945..504d252716f2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -286,7 +286,7 @@ config PWM_MTK_DISP config PWM_MEDIATEK tristate "MediaTek PWM support" - depends on ARCH_MEDIATEK || COMPILE_TEST + depends on ARCH_MEDIATEK || RALINK || COMPILE_TEST help Generic PWM framework driver for Mediatek ARM SoC. diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 771859aca4be..7c8d6a168ceb 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -21,8 +21,18 @@ #define BERLIN_PWM_EN 0x0 #define BERLIN_PWM_ENABLE BIT(0) #define BERLIN_PWM_CONTROL 0x4 -#define BERLIN_PWM_PRESCALE_MASK 0x7 -#define BERLIN_PWM_PRESCALE_MAX 4096 +/* + * The prescaler claims to support 8 different moduli, configured using the + * low three bits of PWM_CONTROL. (Sequentially, they are 1, 4, 8, 16, 64, + * 256, 1024, and 4096.) However, the moduli from 4 to 1024 appear to be + * implemented by internally shifting TCNT left without adding additional + * bits. So, the max TCNT that actually works for a modulus of 4 is 0x3fff; + * for 8, 0x1fff; and so on. This means that those moduli are entirely + * useless, as we could just do the shift ourselves. The 4096 modulus is + * implemented with a real prescaler, so we do use that, but we treat it + * as a flag instead of pretending the modulus is actually configurable. + */ +#define BERLIN_PWM_PRESCALE_4096 0x7 #define BERLIN_PWM_INVERT_POLARITY BIT(3) #define BERLIN_PWM_DUTY 0x8 #define BERLIN_PWM_TCNT 0xc @@ -46,10 +56,6 @@ static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip) return container_of(chip, struct berlin_pwm_chip, chip); } -static const u32 prescaler_table[] = { - 1, 4, 8, 16, 64, 256, 1024, 4096 -}; - static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip, unsigned int channel, unsigned long offset) { @@ -86,33 +92,32 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, int duty_ns, int period_ns) { struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); - unsigned int prescale; + bool prescale_4096 = false; u32 value, duty, period; - u64 cycles, tmp; + u64 cycles; cycles = clk_get_rate(pwm->clk); cycles *= period_ns; do_div(cycles, NSEC_PER_SEC); - for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) { - tmp = cycles; - do_div(tmp, prescaler_table[prescale]); + if (cycles > BERLIN_PWM_MAX_TCNT) { + prescale_4096 = true; + cycles >>= 12; // Prescaled by 4096 - if (tmp <= BERLIN_PWM_MAX_TCNT) - break; + if (cycles > BERLIN_PWM_MAX_TCNT) + return -ERANGE; } - if (tmp > BERLIN_PWM_MAX_TCNT) - return -ERANGE; - - period = tmp; - cycles = tmp * duty_ns; + period = cycles; + cycles *= duty_ns; do_div(cycles, period_ns); duty = cycles; value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); - value &= ~BERLIN_PWM_PRESCALE_MASK; - value |= prescale; + if (prescale_4096) + value |= BERLIN_PWM_PRESCALE_4096; + else + value &= ~BERLIN_PWM_PRESCALE_4096; berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY); diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 9c13694eaa24..98f6ac6cf6ab 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2016 Google, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2, as published by - * the Free Software Foundation. - * * Expose a PWM controlled by the ChromeOS EC to the host processor. + * + * Copyright (C) 2016 Google, Inc. */ #include <linux/module.h> diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 557b4ea16796..883378d055c6 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pwm.h> @@ -75,6 +76,10 @@ enum fsl_pwm_clk { FSL_PWM_CLK_MAX }; +struct fsl_ftm_soc { + bool has_enable_bits; +}; + struct fsl_pwm_chip { struct pwm_chip chip; @@ -87,7 +92,10 @@ struct fsl_pwm_chip { int period_ns; + struct clk *ipg_clk; struct clk *clk[FSL_PWM_CLK_MAX]; + + const struct fsl_ftm_soc *soc; }; static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) @@ -97,16 +105,32 @@ static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { + int ret; struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + ret = clk_prepare_enable(fpc->ipg_clk); + if (!ret && fpc->soc->has_enable_bits) { + mutex_lock(&fpc->lock); + regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), + BIT(pwm->hwpwm + 16)); + mutex_unlock(&fpc->lock); + } + + return ret; } static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + if (fpc->soc->has_enable_bits) { + mutex_lock(&fpc->lock); + regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), + 0); + mutex_unlock(&fpc->lock); + } + + clk_disable_unprepare(fpc->ipg_clk); } static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc, @@ -363,7 +387,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) { int ret; - ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + ret = clk_prepare_enable(fpc->ipg_clk); if (ret) return ret; @@ -371,7 +395,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) regmap_write(fpc->regmap, FTM_OUTINIT, 0x00); regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF); - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + clk_disable_unprepare(fpc->ipg_clk); return 0; } @@ -408,6 +432,7 @@ static int fsl_pwm_probe(struct platform_device *pdev) mutex_init(&fpc->lock); + fpc->soc = of_device_get_match_data(&pdev->dev); fpc->chip.dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -441,6 +466,15 @@ static int fsl_pwm_probe(struct platform_device *pdev) if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN])) return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]); + /* + * ipg_clk is the interface clock for the IP. If not provided, use the + * ftm_sys clock as the default. + */ + fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(fpc->ipg_clk)) + fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS]; + + fpc->chip.ops = &fsl_pwm_ops; fpc->chip.of_xlate = of_pwm_xlate_with_flags; fpc->chip.of_pwm_n_cells = 3; @@ -480,7 +514,7 @@ static int fsl_pwm_suspend(struct device *dev) if (!test_bit(PWMF_REQUESTED, &pwm->flags)) continue; - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + clk_disable_unprepare(fpc->ipg_clk); if (!pwm_is_enabled(pwm)) continue; @@ -503,7 +537,7 @@ static int fsl_pwm_resume(struct device *dev) if (!test_bit(PWMF_REQUESTED, &pwm->flags)) continue; - clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + clk_prepare_enable(fpc->ipg_clk); if (!pwm_is_enabled(pwm)) continue; @@ -524,8 +558,17 @@ static const struct dev_pm_ops fsl_pwm_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume) }; +static const struct fsl_ftm_soc vf610_ftm_pwm = { + .has_enable_bits = false, +}; + +static const struct fsl_ftm_soc imx8qm_ftm_pwm = { + .has_enable_bits = true, +}; + static const struct of_device_id fsl_pwm_dt_ids[] = { - { .compatible = "fsl,vf610-ftm-pwm", }, + { .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm }, + { .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids); diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 08cbe8120588..1d5242c9cde0 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * simple driver for PWM (Pulse Width Modulator) controller * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com> */ diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 328c124773b2..eb6674ce995f 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -57,6 +57,7 @@ static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = { struct mtk_pwm_platform_data { unsigned int num_pwms; bool pwm45_fixup; + bool has_clks; }; /** @@ -86,6 +87,9 @@ static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); int ret; + if (!pc->soc->has_clks) + return 0; + ret = clk_prepare_enable(pc->clks[MTK_CLK_TOP]); if (ret < 0) return ret; @@ -112,6 +116,9 @@ static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + if (!pc->soc->has_clks) + return; + clk_disable_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); @@ -239,7 +246,7 @@ static int mtk_pwm_probe(struct platform_device *pdev) if (IS_ERR(pc->regs)) return PTR_ERR(pc->regs); - for (i = 0; i < data->num_pwms + 2; i++) { + for (i = 0; i < data->num_pwms + 2 && pc->soc->has_clks; i++) { pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); if (IS_ERR(pc->clks[i])) { dev_err(&pdev->dev, "clock: %s fail: %ld\n", @@ -274,22 +281,32 @@ static int mtk_pwm_remove(struct platform_device *pdev) static const struct mtk_pwm_platform_data mt2712_pwm_data = { .num_pwms = 8, .pwm45_fixup = false, + .has_clks = true, }; static const struct mtk_pwm_platform_data mt7622_pwm_data = { .num_pwms = 6, .pwm45_fixup = false, + .has_clks = true, }; static const struct mtk_pwm_platform_data mt7623_pwm_data = { .num_pwms = 5, .pwm45_fixup = true, + .has_clks = true, +}; + +static const struct mtk_pwm_platform_data mt7628_pwm_data = { + .num_pwms = 4, + .pwm45_fixup = true, + .has_clks = false, }; static const struct of_device_id mtk_pwm_of_match[] = { { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, + { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, { }, }; MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 822860b4801a..c1ed641b3e26 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -458,7 +458,6 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, struct meson_pwm_channel *channels) { struct device *dev = meson->chip.dev; - struct device_node *np = dev->of_node; struct clk_init_data init; unsigned int i; char name[255]; @@ -467,7 +466,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, for (i = 0; i < meson->chip.npwm; i++) { struct meson_pwm_channel *channel = &channels[i]; - snprintf(name, sizeof(name), "%pOF#mux%u", np, i); + snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i); init.name = name; init.ops = &clk_mux_ops; diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index a6017ad9926c..04c0f6b95c1a 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -1,12 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2012 Freescale Semiconductor, Inc. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/clk.h> diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 665da3c8fbce..f45798679e3c 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -264,8 +264,9 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) timer_pdata = dev_get_platdata(&timer_pdev->dev); if (!timer_pdata) { - dev_err(&pdev->dev, "dmtimer pdata structure NULL\n"); - ret = -EINVAL; + dev_dbg(&pdev->dev, + "dmtimer pdata structure NULL, deferring probe\n"); + ret = -EPROBE_DEFER; goto put; } diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 7c13e2505080..0059b24cfdc3 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -217,10 +217,8 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev) static int stm32_pwm_lp_remove(struct platform_device *pdev) { struct stm32_pwm_lp *priv = platform_get_drvdata(pdev); - unsigned int i; - for (i = 0; i < priv->chip.npwm; i++) - pwm_disable(&priv->chip.pwms[i]); + pwm_disable(&priv->chip.pwms[0]); return pwmchip_remove(&priv->chip); } diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 4c22cb395040..f7b8a86fa5c5 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -33,10 +33,6 @@ #define TBCTL 0x00 #define TBPRD 0x0A -#define TBCTL_RUN_MASK (BIT(15) | BIT(14)) -#define TBCTL_STOP_NEXT 0 -#define TBCTL_STOP_ON_CYCLE BIT(14) -#define TBCTL_FREE_RUN (BIT(15) | BIT(14)) #define TBCTL_PRDLD_MASK BIT(3) #define TBCTL_PRDLD_SHDW 0 #define TBCTL_PRDLD_IMDT BIT(3) @@ -360,7 +356,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) /* Channels polarity can be configured from action qualifier module */ configure_polarity(pc, pwm->hwpwm); - /* Enable TBCLK before enabling PWM device */ + /* Enable TBCLK */ ret = clk_enable(pc->tbclk); if (ret) { dev_err(chip->dev, "Failed to enable TBCLK for %s: %d\n", @@ -368,9 +364,6 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) return ret; } - /* Enable time counter for free_run */ - ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); - return 0; } @@ -388,6 +381,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) aqcsfrc_mask = AQCSFRC_CSFA_MASK; } + /* Update shadow register first before modifying active register */ + ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); /* * Changes to immediate action on Action Qualifier. This puts * Action Qualifier control on PWM output from next TBCLK @@ -400,9 +395,6 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) /* Disabling TBCLK on PWM disable */ clk_disable(pc->tbclk); - /* Stop Time base counter */ - ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); - /* Disable clock on PWM disable */ pm_runtime_put_sync(chip->dev); } diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index a8cb8d2f2abb..cbe467ff1aba 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c @@ -1006,7 +1006,6 @@ out_free: static int rio_mport_wait_for_async_dma(struct file *filp, void __user *arg) { struct mport_cdev_priv *priv; - struct mport_dev *md; struct rio_async_tx_wait w_param; struct mport_dma_req *req; dma_cookie_t cookie; @@ -1016,7 +1015,6 @@ static int rio_mport_wait_for_async_dma(struct file *filp, void __user *arg) int ret; priv = (struct mport_cdev_priv *)filp->private_data; - md = priv->md; if (unlikely(copy_from_user(&w_param, arg, sizeof(w_param)))) return -EFAULT; diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 2df26f36c687..8cbcd2a3eb20 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -98,7 +98,7 @@ struct da9063_regulator_info { struct da9063_dev_model { const struct da9063_regulator_info *regulator_info; unsigned n_regulators; - unsigned dev_model; + enum da9063_type type; }; /* Single regulator settings */ @@ -530,6 +530,32 @@ static const struct da9063_regulator_info da9063_regulator_info[] = { DA9063_BMEM_ILIM_MASK), }, { + DA9063_LDO(DA9063, LDO3, 900, 20, 3440), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO3_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO3_LIM), + }, + { + DA9063_LDO(DA9063, LDO7, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO7_CONT, DA9063_VLDO7_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO7_LIM), + }, + { + DA9063_LDO(DA9063, LDO8, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO8_CONT, DA9063_VLDO8_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO8_LIM), + }, + { + DA9063_LDO(DA9063, LDO9, 950, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO9_CONT, DA9063_VLDO9_SEL), + }, + { + DA9063_LDO(DA9063, LDO11, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO11_CONT, DA9063_VLDO11_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO11_LIM), + }, + + /* The following LDOs are present only on DA9063, not on DA9063L */ + { DA9063_LDO(DA9063, LDO1, 600, 20, 1860), .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO1_SEL), }, @@ -538,11 +564,6 @@ static const struct da9063_regulator_info da9063_regulator_info[] = { .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO2_SEL), }, { - DA9063_LDO(DA9063, LDO3, 900, 20, 3440), - .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO3_SEL), - .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO3_LIM), - }, - { DA9063_LDO(DA9063, LDO4, 900, 20, 3440), .suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VLDO4_SEL), .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO4_LIM), @@ -555,29 +576,11 @@ static const struct da9063_regulator_info da9063_regulator_info[] = { DA9063_LDO(DA9063, LDO6, 900, 50, 3600), .suspend = BFIELD(DA9063_REG_LDO6_CONT, DA9063_VLDO6_SEL), }, - { - DA9063_LDO(DA9063, LDO7, 900, 50, 3600), - .suspend = BFIELD(DA9063_REG_LDO7_CONT, DA9063_VLDO7_SEL), - .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO7_LIM), - }, - { - DA9063_LDO(DA9063, LDO8, 900, 50, 3600), - .suspend = BFIELD(DA9063_REG_LDO8_CONT, DA9063_VLDO8_SEL), - .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO8_LIM), - }, - { - DA9063_LDO(DA9063, LDO9, 950, 50, 3600), - .suspend = BFIELD(DA9063_REG_LDO9_CONT, DA9063_VLDO9_SEL), - }, + { DA9063_LDO(DA9063, LDO10, 900, 50, 3600), .suspend = BFIELD(DA9063_REG_LDO10_CONT, DA9063_VLDO10_SEL), }, - { - DA9063_LDO(DA9063, LDO11, 900, 50, 3600), - .suspend = BFIELD(DA9063_REG_LDO11_CONT, DA9063_VLDO11_SEL), - .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO11_LIM), - }, }; /* Link chip model with regulators info table */ @@ -585,7 +588,12 @@ static struct da9063_dev_model regulators_models[] = { { .regulator_info = da9063_regulator_info, .n_regulators = ARRAY_SIZE(da9063_regulator_info), - .dev_model = PMIC_DA9063, + .type = PMIC_TYPE_DA9063, + }, + { + .regulator_info = da9063_regulator_info, + .n_regulators = ARRAY_SIZE(da9063_regulator_info) - 6, + .type = PMIC_TYPE_DA9063L, }, { } }; @@ -641,28 +649,34 @@ static struct of_regulator_match da9063_matches[] = { [DA9063_ID_BPERI] = { .name = "bperi", }, [DA9063_ID_BCORES_MERGED] = { .name = "bcores-merged" }, [DA9063_ID_BMEM_BIO_MERGED] = { .name = "bmem-bio-merged", }, + [DA9063_ID_LDO3] = { .name = "ldo3", }, + [DA9063_ID_LDO7] = { .name = "ldo7", }, + [DA9063_ID_LDO8] = { .name = "ldo8", }, + [DA9063_ID_LDO9] = { .name = "ldo9", }, + [DA9063_ID_LDO11] = { .name = "ldo11", }, + /* The following LDOs are present only on DA9063, not on DA9063L */ [DA9063_ID_LDO1] = { .name = "ldo1", }, [DA9063_ID_LDO2] = { .name = "ldo2", }, - [DA9063_ID_LDO3] = { .name = "ldo3", }, [DA9063_ID_LDO4] = { .name = "ldo4", }, [DA9063_ID_LDO5] = { .name = "ldo5", }, [DA9063_ID_LDO6] = { .name = "ldo6", }, - [DA9063_ID_LDO7] = { .name = "ldo7", }, - [DA9063_ID_LDO8] = { .name = "ldo8", }, - [DA9063_ID_LDO9] = { .name = "ldo9", }, [DA9063_ID_LDO10] = { .name = "ldo10", }, - [DA9063_ID_LDO11] = { .name = "ldo11", }, }; static struct da9063_regulators_pdata *da9063_parse_regulators_dt( struct platform_device *pdev, struct of_regulator_match **da9063_reg_matches) { + struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); struct da9063_regulators_pdata *pdata; struct da9063_regulator_data *rdata; struct device_node *node; + int da9063_matches_len = ARRAY_SIZE(da9063_matches); int i, n, num; + if (da9063->type == PMIC_TYPE_DA9063L) + da9063_matches_len -= 6; + node = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!node) { dev_err(&pdev->dev, "Regulators device node not found\n"); @@ -670,7 +684,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( } num = of_regulator_match(&pdev->dev, node, da9063_matches, - ARRAY_SIZE(da9063_matches)); + da9063_matches_len); of_node_put(node); if (num < 0) { dev_err(&pdev->dev, "Failed to match regulators\n"); @@ -689,7 +703,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( pdata->n_regulators = num; n = 0; - for (i = 0; i < ARRAY_SIZE(da9063_matches); i++) { + for (i = 0; i < da9063_matches_len; i++) { if (!da9063_matches[i].init_data) continue; @@ -741,12 +755,12 @@ static int da9063_regulator_probe(struct platform_device *pdev) /* Find regulators set for particular device model */ for (model = regulators_models; model->regulator_info; model++) { - if (model->dev_model == da9063->model) + if (model->type == da9063->type) break; } if (!model->regulator_info) { dev_err(&pdev->dev, "Chip model not recognised (%u)\n", - da9063->model); + da9063->type); return -ENODEV; } diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c0b292be1b72..13d28fdbdbb5 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -73,6 +73,13 @@ config RESET_MESON help This enables the reset driver for Amlogic Meson SoCs. +config RESET_MESON_AUDIO_ARB + tristate "Meson Audio Memory Arbiter Reset Driver" + depends on ARCH_MESON || COMPILE_TEST + help + This enables the reset driver for Audio Memory Arbiter of + Amlogic's A113 based SoCs + config RESET_OXNAS bool @@ -82,6 +89,15 @@ config RESET_PISTACHIO help This enables the reset driver for ImgTec Pistachio SoCs. +config RESET_QCOM_AOSS + bool "Qcom AOSS Reset Driver" + depends on ARCH_QCOM || COMPILE_TEST + help + This enables the AOSS (always on subsystem) reset driver + for Qualcomm SDM845 SoCs. Say Y if you want to control + reset signals provided by AOSS for Modem, Venus, ADSP, + GPU, Camera, Wireless, Display subsystem. Otherwise, say N. + config RESET_SIMPLE bool "Simple Reset Controller Driver" if COMPILE_TEST default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED @@ -138,6 +154,16 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block. +config RESET_UNIPHIER_USB3 + tristate "USB3 reset driver for UniPhier SoCs" + depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF + default ARCH_UNIPHIER + select RESET_SIMPLE + help + Support for the USB3 core reset on UniPhier SoCs. + Say Y if you want to control reset signals provided by + USB3 glue layer. + config RESET_ZYNQ bool "ZYNQ Reset Driver" if COMPILE_TEST default ARCH_ZYNQ diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index c1261dcfe9ad..4243c38228e2 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -12,13 +12,16 @@ obj-$(CONFIG_RESET_IMX7) += reset-imx7.o obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MESON) += reset-meson.o +obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o +obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o +obj-$(CONFIG_RESET_UNIPHIER_USB3) += reset-uniphier-usb3.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index 14bc78d28707..97d9f08271c5 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -81,7 +81,7 @@ static int imx7_reset_set(struct reset_controller_dev *rcdev, { struct imx7_src *imx7src = to_imx7_src(rcdev); const struct imx7_src_signal *signal = &imx7_src_signals[id]; - unsigned int value = 0; + unsigned int value = assert ? signal->bit : 0; switch (id) { case IMX7_RESET_PCIEPHY: diff --git a/drivers/reset/reset-meson-audio-arb.c b/drivers/reset/reset-meson-audio-arb.c new file mode 100644 index 000000000000..91751617b37a --- /dev/null +++ b/drivers/reset/reset-meson-audio-arb.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet <jbrunet@baylibre.com> + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/reset-controller.h> +#include <linux/spinlock.h> + +#include <dt-bindings/reset/amlogic,meson-axg-audio-arb.h> + +struct meson_audio_arb_data { + struct reset_controller_dev rstc; + void __iomem *regs; + struct clk *clk; + const unsigned int *reset_bits; + spinlock_t lock; +}; + +#define ARB_GENERAL_BIT 31 + +static const unsigned int axg_audio_arb_reset_bits[] = { + [AXG_ARB_TODDR_A] = 0, + [AXG_ARB_TODDR_B] = 1, + [AXG_ARB_TODDR_C] = 2, + [AXG_ARB_FRDDR_A] = 4, + [AXG_ARB_FRDDR_B] = 5, + [AXG_ARB_FRDDR_C] = 6, +}; + +static int meson_audio_arb_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + u32 val; + struct meson_audio_arb_data *arb = + container_of(rcdev, struct meson_audio_arb_data, rstc); + + spin_lock(&arb->lock); + val = readl(arb->regs); + + if (assert) + val &= ~BIT(arb->reset_bits[id]); + else + val |= BIT(arb->reset_bits[id]); + + writel(val, arb->regs); + spin_unlock(&arb->lock); + + return 0; +} + +static int meson_audio_arb_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + u32 val; + struct meson_audio_arb_data *arb = + container_of(rcdev, struct meson_audio_arb_data, rstc); + + val = readl(arb->regs); + + return !(val & BIT(arb->reset_bits[id])); +} + +static int meson_audio_arb_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_audio_arb_update(rcdev, id, true); +} + +static int meson_audio_arb_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_audio_arb_update(rcdev, id, false); +} + +static const struct reset_control_ops meson_audio_arb_rstc_ops = { + .assert = meson_audio_arb_assert, + .deassert = meson_audio_arb_deassert, + .status = meson_audio_arb_status, +}; + +static const struct of_device_id meson_audio_arb_of_match[] = { + { .compatible = "amlogic,meson-axg-audio-arb", }, + {} +}; +MODULE_DEVICE_TABLE(of, meson_audio_arb_of_match); + +static int meson_audio_arb_remove(struct platform_device *pdev) +{ + struct meson_audio_arb_data *arb = platform_get_drvdata(pdev); + + /* Disable all access */ + spin_lock(&arb->lock); + writel(0, arb->regs); + spin_unlock(&arb->lock); + + clk_disable_unprepare(arb->clk); + + return 0; +} + +static int meson_audio_arb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct meson_audio_arb_data *arb; + struct resource *res; + int ret; + + arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL); + if (!arb) + return -ENOMEM; + platform_set_drvdata(pdev, arb); + + arb->clk = devm_clk_get(dev, NULL); + if (IS_ERR(arb->clk)) { + if (PTR_ERR(arb->clk) != -EPROBE_DEFER) + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(arb->clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + arb->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(arb->regs)) + return PTR_ERR(arb->regs); + + spin_lock_init(&arb->lock); + arb->reset_bits = axg_audio_arb_reset_bits; + arb->rstc.nr_resets = ARRAY_SIZE(axg_audio_arb_reset_bits); + arb->rstc.ops = &meson_audio_arb_rstc_ops; + arb->rstc.of_node = dev->of_node; + + /* + * Enable general : + * In the initial state, all memory interfaces are disabled + * and the general bit is on + */ + ret = clk_prepare_enable(arb->clk); + if (ret) { + dev_err(dev, "failed to enable arb clock\n"); + return ret; + } + writel(BIT(ARB_GENERAL_BIT), arb->regs); + + /* Register reset controller */ + ret = devm_reset_controller_register(dev, &arb->rstc); + if (ret) { + dev_err(dev, "failed to register arb reset controller\n"); + meson_audio_arb_remove(pdev); + } + + return ret; +} + +static struct platform_driver meson_audio_arb_pdrv = { + .probe = meson_audio_arb_probe, + .remove = meson_audio_arb_remove, + .driver = { + .name = "meson-audio-arb-reset", + .of_match_table = meson_audio_arb_of_match, + }, +}; +module_platform_driver(meson_audio_arb_pdrv); + +MODULE_DESCRIPTION("Amlogic A113 Audio Memory Arbiter"); +MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-qcom-aoss.c b/drivers/reset/reset-qcom-aoss.c new file mode 100644 index 000000000000..36db96750450 --- /dev/null +++ b/drivers/reset/reset-qcom-aoss.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of_device.h> +#include <dt-bindings/reset/qcom,sdm845-aoss.h> + +struct qcom_aoss_reset_map { + unsigned int reg; +}; + +struct qcom_aoss_desc { + const struct qcom_aoss_reset_map *resets; + size_t num_resets; +}; + +struct qcom_aoss_reset_data { + struct reset_controller_dev rcdev; + void __iomem *base; + const struct qcom_aoss_desc *desc; +}; + +static const struct qcom_aoss_reset_map sdm845_aoss_resets[] = { + [AOSS_CC_MSS_RESTART] = {0x10000}, + [AOSS_CC_CAMSS_RESTART] = {0x11000}, + [AOSS_CC_VENUS_RESTART] = {0x12000}, + [AOSS_CC_GPU_RESTART] = {0x13000}, + [AOSS_CC_DISPSS_RESTART] = {0x14000}, + [AOSS_CC_WCSS_RESTART] = {0x20000}, + [AOSS_CC_LPASS_RESTART] = {0x30000}, +}; + +static const struct qcom_aoss_desc sdm845_aoss_desc = { + .resets = sdm845_aoss_resets, + .num_resets = ARRAY_SIZE(sdm845_aoss_resets), +}; + +static inline struct qcom_aoss_reset_data *to_qcom_aoss_reset_data( + struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct qcom_aoss_reset_data, rcdev); +} + +static int qcom_aoss_control_assert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev); + const struct qcom_aoss_reset_map *map = &data->desc->resets[idx]; + + writel(1, data->base + map->reg); + /* Wait 6 32kHz sleep cycles for reset */ + usleep_range(200, 300); + return 0; +} + +static int qcom_aoss_control_deassert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev); + const struct qcom_aoss_reset_map *map = &data->desc->resets[idx]; + + writel(0, data->base + map->reg); + /* Wait 6 32kHz sleep cycles for reset */ + usleep_range(200, 300); + return 0; +} + +static int qcom_aoss_control_reset(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + qcom_aoss_control_assert(rcdev, idx); + + return qcom_aoss_control_deassert(rcdev, idx); +} + +static const struct reset_control_ops qcom_aoss_reset_ops = { + .reset = qcom_aoss_control_reset, + .assert = qcom_aoss_control_assert, + .deassert = qcom_aoss_control_deassert, +}; + +static int qcom_aoss_reset_probe(struct platform_device *pdev) +{ + struct qcom_aoss_reset_data *data; + struct device *dev = &pdev->dev; + const struct qcom_aoss_desc *desc; + struct resource *res; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->desc = desc; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + data->rcdev.owner = THIS_MODULE; + data->rcdev.ops = &qcom_aoss_reset_ops; + data->rcdev.nr_resets = desc->num_resets; + data->rcdev.of_node = dev->of_node; + + return devm_reset_controller_register(dev, &data->rcdev); +} + +static const struct of_device_id qcom_aoss_reset_of_match[] = { + { .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc }, + {} +}; + +static struct platform_driver qcom_aoss_reset_driver = { + .probe = qcom_aoss_reset_probe, + .driver = { + .name = "qcom_aoss_reset", + .of_match_table = qcom_aoss_reset_of_match, + }, +}; + +builtin_platform_driver(qcom_aoss_reset_driver); + +MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index f7ce8910a392..a91107fc9e27 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -87,6 +87,7 @@ const struct reset_control_ops reset_simple_ops = { .deassert = reset_simple_deassert, .status = reset_simple_status, }; +EXPORT_SYMBOL_GPL(reset_simple_ops); /** * struct reset_simple_devdata - simple reset controller properties diff --git a/drivers/reset/reset-uniphier-usb3.c b/drivers/reset/reset-uniphier-usb3.c new file mode 100644 index 000000000000..ffa1b19b594d --- /dev/null +++ b/drivers/reset/reset-uniphier-usb3.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// reset-uniphier-usb3.c - USB3 reset driver for UniPhier +// Copyright 2018 Socionext Inc. +// Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include "reset-simple.h" + +#define MAX_CLKS 2 +#define MAX_RSTS 2 + +struct uniphier_usb3_reset_soc_data { + int nclks; + const char * const *clock_names; + int nrsts; + const char * const *reset_names; +}; + +struct uniphier_usb3_reset_priv { + struct clk_bulk_data clk[MAX_CLKS]; + struct reset_control *rst[MAX_RSTS]; + struct reset_simple_data rdata; + const struct uniphier_usb3_reset_soc_data *data; +}; + +static int uniphier_usb3_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_usb3_reset_priv *priv; + struct resource *res; + resource_size_t size; + const char *name; + int i, ret, nr; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data || priv->data->nclks > MAX_CLKS || + priv->data->nrsts > MAX_RSTS)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + size = resource_size(res); + priv->rdata.membase = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->rdata.membase)) + return PTR_ERR(priv->rdata.membase); + + for (i = 0; i < priv->data->nclks; i++) + priv->clk[i].id = priv->data->clock_names[i]; + ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (i = 0; i < priv->data->nrsts; i++) { + name = priv->data->reset_names[i]; + priv->rst[i] = devm_reset_control_get_shared(dev, name); + if (IS_ERR(priv->rst[i])) + return PTR_ERR(priv->rst[i]); + } + + ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (nr = 0; nr < priv->data->nrsts; nr++) { + ret = reset_control_deassert(priv->rst[nr]); + if (ret) + goto out_rst_assert; + } + + spin_lock_init(&priv->rdata.lock); + priv->rdata.rcdev.owner = THIS_MODULE; + priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE; + priv->rdata.rcdev.ops = &reset_simple_ops; + priv->rdata.rcdev.of_node = dev->of_node; + priv->rdata.active_low = true; + + platform_set_drvdata(pdev, priv); + + ret = devm_reset_controller_register(dev, &priv->rdata.rcdev); + if (ret) + goto out_rst_assert; + + return 0; + +out_rst_assert: + while (nr--) + reset_control_assert(priv->rst[nr]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return ret; +} + +static int uniphier_usb3_reset_remove(struct platform_device *pdev) +{ + struct uniphier_usb3_reset_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->data->nrsts; i++) + reset_control_assert(priv->rst[i]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return 0; +} + +static const char * const uniphier_pro4_clock_reset_names[] = { + "gio", "link", +}; + +static const struct uniphier_usb3_reset_soc_data uniphier_pro4_data = { + .nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .clock_names = uniphier_pro4_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .reset_names = uniphier_pro4_clock_reset_names, +}; + +static const char * const uniphier_pxs2_clock_reset_names[] = { + "link", +}; + +static const struct uniphier_usb3_reset_soc_data uniphier_pxs2_data = { + .nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .clock_names = uniphier_pxs2_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .reset_names = uniphier_pxs2_clock_reset_names, +}; + +static const struct of_device_id uniphier_usb3_reset_match[] = { + { + .compatible = "socionext,uniphier-pro4-usb3-reset", + .data = &uniphier_pro4_data, + }, + { + .compatible = "socionext,uniphier-pxs2-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_usb3_reset_match); + +static struct platform_driver uniphier_usb3_reset_driver = { + .probe = uniphier_usb3_reset_probe, + .remove = uniphier_usb3_reset_remove, + .driver = { + .name = "uniphier-usb3-reset", + .of_match_table = uniphier_usb3_reset_match, + }, +}; +module_platform_driver(uniphier_usb3_reset_driver); + +MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); +MODULE_DESCRIPTION("UniPhier USB3 Reset Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index e9030ff1bf2f..5605745663ae 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -202,6 +202,12 @@ static const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = { #define UNIPHIER_PERI_RESET_FI2C(id, ch) \ UNIPHIER_RESETX((id), 0x114, 24 + (ch)) +#define UNIPHIER_PERI_RESET_SCSSI(id) \ + UNIPHIER_RESETX((id), 0x110, 17) + +#define UNIPHIER_PERI_RESET_MCSSI(id) \ + UNIPHIER_RESETX((id), 0x114, 14) + static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { UNIPHIER_PERI_RESET_UART(0, 0), UNIPHIER_PERI_RESET_UART(1, 1), @@ -212,6 +218,7 @@ static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { UNIPHIER_PERI_RESET_I2C(6, 2), UNIPHIER_PERI_RESET_I2C(7, 3), UNIPHIER_PERI_RESET_I2C(8, 4), + UNIPHIER_PERI_RESET_SCSSI(11), UNIPHIER_RESET_END, }; @@ -227,6 +234,8 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = { UNIPHIER_PERI_RESET_FI2C(8, 4), UNIPHIER_PERI_RESET_FI2C(9, 5), UNIPHIER_PERI_RESET_FI2C(10, 6), + UNIPHIER_PERI_RESET_SCSSI(11), + UNIPHIER_PERI_RESET_MCSSI(12), UNIPHIER_RESET_END, }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a2ba5db36145..7d7be60a2413 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -244,15 +244,6 @@ config RTC_DRV_DS1307 This driver can also be built as a module. If so, the module will be called rtc-ds1307. -config RTC_DRV_DS1307_HWMON - bool "HWMON support for rtc-ds1307" - depends on RTC_DRV_DS1307 && HWMON - depends on !(RTC_DRV_DS1307=y && HWMON=m) - default y - help - Say Y here if you want to expose temperature sensor data on - rtc-ds1307 (only DS3231) - config RTC_DRV_DS1307_CENTURY bool "Century bit support for rtc-ds1307" depends on RTC_DRV_DS1307 @@ -1027,18 +1018,6 @@ config RTC_DS1685_PROC_REGS Unless you are debugging this driver, choose N. -config RTC_DS1685_SYSFS_REGS - bool "SysFS access to RTC register bits" - depends on RTC_DRV_DS1685_FAMILY && SYSFS - help - Enable this to provide access to the RTC control register bits - in /sys. Some of the bits are read-write, others are read-only. - - Keep in mind that reading Control C's bits automatically clears - all pending IRQ flags - this can cause lost interrupts. - - If you know that you need access to these bits, choose Y, Else N. - config RTC_DRV_DS1742 tristate "Maxim/Dallas DS1742/1743" depends on HAS_IOMEM diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index d37588f08055..0fca4d74c76b 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -68,7 +68,7 @@ static int rtc_suspend(struct device *dev) return 0; } - getnstimeofday64(&old_system); + ktime_get_real_ts64(&old_system); old_rtc.tv_sec = rtc_tm_to_time64(&tm); @@ -110,7 +110,7 @@ static int rtc_resume(struct device *dev) return 0; /* snapshot the current rtc and system time at resume */ - getnstimeofday64(&new_system); + ktime_get_real_ts64(&new_system); err = rtc_read_time(rtc, &tm); if (err < 0) { pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev)); @@ -172,7 +172,6 @@ static struct rtc_device *rtc_allocate_device(void) mutex_init(&rtc->ops_lock); spin_lock_init(&rtc->irq_lock); - spin_lock_init(&rtc->irq_task_lock); init_waitqueue_head(&rtc->irq_queue); /* Init timerqueue */ diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index bac1eeb3d312..3d577e259e91 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -607,12 +607,6 @@ void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); spin_unlock_irqrestore(&rtc->irq_lock, flags); - /* call the task func */ - spin_lock_irqsave(&rtc->irq_task_lock, flags); - if (rtc->irq_task) - rtc->irq_task->func(rtc->irq_task->private_data); - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - wake_up_interruptible(&rtc->irq_queue); kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); } @@ -721,39 +715,6 @@ void rtc_class_close(struct rtc_device *rtc) } EXPORT_SYMBOL_GPL(rtc_class_close); -int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) -{ - int retval = -EBUSY; - - if (task == NULL || task->func == NULL) - return -EINVAL; - - /* Cannot register while the char dev is in use */ - if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) - return -EBUSY; - - spin_lock_irq(&rtc->irq_task_lock); - if (rtc->irq_task == NULL) { - rtc->irq_task = task; - retval = 0; - } - spin_unlock_irq(&rtc->irq_task_lock); - - clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); - - return retval; -} -EXPORT_SYMBOL_GPL(rtc_irq_register); - -void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) -{ - spin_lock_irq(&rtc->irq_task_lock); - if (rtc->irq_task == task) - rtc->irq_task = NULL; - spin_unlock_irq(&rtc->irq_task_lock); -} -EXPORT_SYMBOL_GPL(rtc_irq_unregister); - static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled) { /* @@ -785,71 +746,45 @@ static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled) * Context: any * * Note that rtc_irq_set_freq() should previously have been used to - * specify the desired frequency of periodic IRQ task->func() callbacks. + * specify the desired frequency of periodic IRQ. */ -int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) +int rtc_irq_set_state(struct rtc_device *rtc, int enabled) { int err = 0; - unsigned long flags; -retry: - spin_lock_irqsave(&rtc->irq_task_lock, flags); - if (rtc->irq_task != NULL && task == NULL) - err = -EBUSY; - else if (rtc->irq_task != task) - err = -EACCES; - else { - if (rtc_update_hrtimer(rtc, enabled) < 0) { - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - cpu_relax(); - goto retry; - } - rtc->pie_enabled = enabled; - } - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); + while (rtc_update_hrtimer(rtc, enabled) < 0) + cpu_relax(); + + rtc->pie_enabled = enabled; trace_rtc_irq_set_state(enabled, err); return err; } -EXPORT_SYMBOL_GPL(rtc_irq_set_state); /** * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ * @rtc: the rtc device * @task: currently registered with rtc_irq_register() - * @freq: positive frequency with which task->func() will be called + * @freq: positive frequency * Context: any * * Note that rtc_irq_set_state() is used to enable or disable the * periodic IRQs. */ -int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) +int rtc_irq_set_freq(struct rtc_device *rtc, int freq) { int err = 0; - unsigned long flags; if (freq <= 0 || freq > RTC_MAX_FREQ) return -EINVAL; -retry: - spin_lock_irqsave(&rtc->irq_task_lock, flags); - if (rtc->irq_task != NULL && task == NULL) - err = -EBUSY; - else if (rtc->irq_task != task) - err = -EACCES; - else { - rtc->irq_freq = freq; - if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) { - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - cpu_relax(); - goto retry; - } - } - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); + + rtc->irq_freq = freq; + while (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) + cpu_relax(); trace_rtc_irq_set_freq(freq, err); return err; } -EXPORT_SYMBOL_GPL(rtc_irq_set_freq); /** * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue @@ -979,8 +914,8 @@ again: timerqueue_del(&rtc->timerqueue, &timer->node); trace_rtc_timer_dequeue(timer); timer->enabled = 0; - if (timer->task.func) - timer->task.func(timer->task.private_data); + if (timer->func) + timer->func(timer->private_data); trace_rtc_timer_fired(timer); /* Re-add/fwd periodic timers */ @@ -1035,8 +970,8 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data) { timerqueue_init(&timer->node); timer->enabled = 0; - timer->task.func = f; - timer->task.private_data = data; + timer->func = f; + timer->private_data = data; } /* rtc_timer_start - Sets an rtc_timer to fire in the future diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 1e4978c96ffd..bde53c8ccee2 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -30,6 +30,8 @@ #define RTC_IRQ_FREQ_1HZ BIT(2) #define RTC_CCR 0x18 #define RTC_CCR_MODE BIT(15) +#define RTC_CONF_TEST 0x1C +#define RTC_NOMINAL_TIMING BIT(13) #define RTC_TIME 0xC #define RTC_ALARM1 0x10 @@ -75,6 +77,7 @@ struct armada38x_rtc { void __iomem *regs_soc; spinlock_t lock; int irq; + bool initialized; struct value_to_freq *val_to_freq; struct armada38x_rtc_data *data; }; @@ -226,6 +229,23 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } +static void armada38x_rtc_reset(struct armada38x_rtc *rtc) +{ + u32 reg; + + reg = rtc->data->read_rtc_reg(rtc, RTC_CONF_TEST); + /* If bits [7:0] are non-zero, assume RTC was uninitialized */ + if (reg & 0xff) { + rtc_delayed_write(0, rtc, RTC_CONF_TEST); + msleep(500); /* Oscillator startup time */ + rtc_delayed_write(0, rtc, RTC_TIME); + rtc_delayed_write(SOC_RTC_ALARM1 | SOC_RTC_ALARM2, rtc, + RTC_STATUS); + rtc_delayed_write(RTC_NOMINAL_TIMING, rtc, RTC_CCR); + } + rtc->initialized = true; +} + static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); @@ -237,6 +257,9 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) if (ret) goto out; + if (!rtc->initialized) + armada38x_rtc_reset(rtc); + spin_lock_irqsave(&rtc->lock, flags); rtc_delayed_write(time, rtc, RTC_TIME); spin_unlock_irqrestore(&rtc->lock, flags); diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index d768f6747961..113493b52149 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -162,6 +162,10 @@ static int bq4802_probe(struct platform_device *pdev) } else if (p->r->flags & IORESOURCE_MEM) { p->regs = devm_ioremap(&pdev->dev, p->r->start, resource_size(p->r)); + if (!p->regs){ + err = -ENOMEM; + goto out; + } p->read = bq4802_read_mem; p->write = bq4802_write_mem; } else { diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h index 0abf98983e13..ccc17a2e293d 100644 --- a/drivers/rtc/rtc-core.h +++ b/drivers/rtc/rtc-core.h @@ -40,9 +40,23 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc) #ifdef CONFIG_RTC_INTF_SYSFS const struct attribute_group **rtc_get_dev_attribute_groups(void); +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp); +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps); #else static inline const struct attribute_group **rtc_get_dev_attribute_groups(void) { return NULL; } + +static inline +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) +{ + return 0; +} + +static inline +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) +{ + return 0; +} #endif diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index efa221e8bc22..43d962a9c210 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -341,11 +341,11 @@ static long rtc_dev_ioctl(struct file *file, return rtc_set_time(rtc, &tm); case RTC_PIE_ON: - err = rtc_irq_set_state(rtc, NULL, 1); + err = rtc_irq_set_state(rtc, 1); break; case RTC_PIE_OFF: - err = rtc_irq_set_state(rtc, NULL, 0); + err = rtc_irq_set_state(rtc, 0); break; case RTC_AIE_ON: @@ -365,7 +365,7 @@ static long rtc_dev_ioctl(struct file *file, return rtc_update_irq_enable(rtc, 0); case RTC_IRQP_SET: - err = rtc_irq_set_freq(rtc, NULL, arg); + err = rtc_irq_set_freq(rtc, arg); break; case RTC_IRQP_READ: @@ -427,7 +427,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file) /* Keep ioctl until all drivers are converted */ rtc_dev_ioctl(file, RTC_UIE_OFF, 0); rtc_update_irq_enable(rtc, 0); - rtc_irq_set_state(rtc, NULL, 0); + rtc_irq_set_state(rtc, 0); clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); return 0; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e9ec4160d7f6..4b2b4627daeb 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -44,6 +44,7 @@ enum ds_type { ds_3231, m41t0, m41t00, + m41t11, mcp794xx, rx_8025, rx_8130, @@ -227,6 +228,11 @@ static const struct chip_desc chips[last_ds_type] = { .irq_handler = rx8130_irq, .rtc_ops = &rx8130_rtc_ops, }, + [m41t11] = { + /* this is battery backed SRAM */ + .nvram_offset = 8, + .nvram_size = 56, + }, [mcp794xx] = { .alarm = 1, /* this is battery backed SRAM */ @@ -249,6 +255,7 @@ static const struct i2c_device_id ds1307_id[] = { { "ds3231", ds_3231 }, { "m41t0", m41t0 }, { "m41t00", m41t00 }, + { "m41t11", m41t11 }, { "mcp7940x", mcp794xx }, { "mcp7941x", mcp794xx }, { "pt7c4338", ds_1307 }, @@ -299,13 +306,17 @@ static const struct of_device_id ds1307_of_match[] = { }, { .compatible = "st,m41t0", - .data = (void *)m41t00 + .data = (void *)m41t0 }, { .compatible = "st,m41t00", .data = (void *)m41t00 }, { + .compatible = "st,m41t11", + .data = (void *)m41t11 + }, + { .compatible = "microchip,mcp7940x", .data = (void *)mcp794xx }, @@ -347,6 +358,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = { { .id = "DS3231", .driver_data = ds_3231 }, { .id = "M41T0", .driver_data = m41t0 }, { .id = "M41T00", .driver_data = m41t00 }, + { .id = "M41T11", .driver_data = m41t11 }, { .id = "MCP7940X", .driver_data = mcp794xx }, { .id = "MCP7941X", .driver_data = mcp794xx }, { .id = "PT7C4338", .driver_data = ds_1307 }, @@ -1030,7 +1042,7 @@ static u8 ds1307_trickle_init(struct ds1307 *ds1307, /*----------------------------------------------------------------------*/ -#ifdef CONFIG_RTC_DRV_DS1307_HWMON +#if IS_REACHABLE(CONFIG_HWMON) /* * Temperature sensor support for ds3231 devices. @@ -1576,6 +1588,7 @@ read_rtc: case ds_1307: case m41t0: case m41t00: + case m41t11: /* clock halted? turn it on, so clock can tick. */ if (tmp & DS1307_BIT_CH) { regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); @@ -1641,6 +1654,7 @@ read_rtc: case ds_1340: case m41t0: case m41t00: + case m41t11: /* * NOTE: ignores century bits; fix before deploying * systems that will run through year 2100. diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 5c0db6c8134c..6f39f683a98c 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1188,552 +1188,6 @@ ds1685_rtc_sysfs_misc_grp = { .attrs = ds1685_rtc_sysfs_misc_attrs, }; -#ifdef CONFIG_RTC_DS1685_SYSFS_REGS -/** - * struct ds1685_rtc_ctrl_regs. - * @name: char pointer for the bit name. - * @reg: control register the bit is in. - * @bit: the bit's offset in the register. - */ -struct ds1685_rtc_ctrl_regs { - const char *name; - const u8 reg; - const u8 bit; -}; - -/* - * Ctrl register bit lookup table. - */ -static const struct ds1685_rtc_ctrl_regs -ds1685_ctrl_regs_table[] = { - { "uip", RTC_CTRL_A, RTC_CTRL_A_UIP }, - { "dv2", RTC_CTRL_A, RTC_CTRL_A_DV2 }, - { "dv1", RTC_CTRL_A, RTC_CTRL_A_DV1 }, - { "dv0", RTC_CTRL_A, RTC_CTRL_A_DV0 }, - { "rs3", RTC_CTRL_A, RTC_CTRL_A_RS3 }, - { "rs2", RTC_CTRL_A, RTC_CTRL_A_RS2 }, - { "rs1", RTC_CTRL_A, RTC_CTRL_A_RS1 }, - { "rs0", RTC_CTRL_A, RTC_CTRL_A_RS0 }, - { "set", RTC_CTRL_B, RTC_CTRL_B_SET }, - { "pie", RTC_CTRL_B, RTC_CTRL_B_PIE }, - { "aie", RTC_CTRL_B, RTC_CTRL_B_AIE }, - { "uie", RTC_CTRL_B, RTC_CTRL_B_UIE }, - { "sqwe", RTC_CTRL_B, RTC_CTRL_B_SQWE }, - { "dm", RTC_CTRL_B, RTC_CTRL_B_DM }, - { "2412", RTC_CTRL_B, RTC_CTRL_B_2412 }, - { "dse", RTC_CTRL_B, RTC_CTRL_B_DSE }, - { "irqf", RTC_CTRL_C, RTC_CTRL_C_IRQF }, - { "pf", RTC_CTRL_C, RTC_CTRL_C_PF }, - { "af", RTC_CTRL_C, RTC_CTRL_C_AF }, - { "uf", RTC_CTRL_C, RTC_CTRL_C_UF }, - { "vrt", RTC_CTRL_D, RTC_CTRL_D_VRT }, - { "vrt2", RTC_EXT_CTRL_4A, RTC_CTRL_4A_VRT2 }, - { "incr", RTC_EXT_CTRL_4A, RTC_CTRL_4A_INCR }, - { "pab", RTC_EXT_CTRL_4A, RTC_CTRL_4A_PAB }, - { "rf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_RF }, - { "wf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_WF }, - { "kf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_KF }, -#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689) - { "bme", RTC_EXT_CTRL_4A, RTC_CTRL_4A_BME }, -#endif - { "abe", RTC_EXT_CTRL_4B, RTC_CTRL_4B_ABE }, - { "e32k", RTC_EXT_CTRL_4B, RTC_CTRL_4B_E32K }, - { "cs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_CS }, - { "rce", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RCE }, - { "prs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_PRS }, - { "rie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RIE }, - { "wie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_WIE }, - { "kse", RTC_EXT_CTRL_4B, RTC_CTRL_4B_KSE }, - { NULL, 0, 0 }, -}; - -/** - * ds1685_rtc_sysfs_ctrl_regs_lookup - ctrl register bit lookup function. - * @name: ctrl register bit to look up in ds1685_ctrl_regs_table. - */ -static const struct ds1685_rtc_ctrl_regs* -ds1685_rtc_sysfs_ctrl_regs_lookup(const char *name) -{ - const struct ds1685_rtc_ctrl_regs *p = ds1685_ctrl_regs_table; - - for (; p->name != NULL; ++p) - if (strcmp(p->name, name) == 0) - return p; - - return NULL; -} - -/** - * ds1685_rtc_sysfs_ctrl_regs_show - reads a ctrl register bit via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - */ -static ssize_t -ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 tmp; - struct ds1685_priv *rtc = dev_get_drvdata(dev); - const struct ds1685_rtc_ctrl_regs *reg_info = - ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name); - - /* Make sure we actually matched something. */ - if (!reg_info) - return -EINVAL; - - /* No spinlock during a read -- mutex is already held. */ - ds1685_rtc_switch_to_bank1(rtc); - tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit; - ds1685_rtc_switch_to_bank0(rtc); - - return sprintf(buf, "%d\n", (tmp ? 1 : 0)); -} - -/** - * ds1685_rtc_sysfs_ctrl_regs_store - writes a ctrl register bit via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - * @count: number of bytes written. - */ -static ssize_t -ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ds1685_priv *rtc = dev_get_drvdata(dev); - u8 reg = 0, bit = 0, tmp; - unsigned long flags; - long int val = 0; - const struct ds1685_rtc_ctrl_regs *reg_info = - ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name); - - /* We only accept numbers. */ - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; - - /* bits are binary, 0 or 1 only. */ - if ((val != 0) && (val != 1)) - return -ERANGE; - - /* Make sure we actually matched something. */ - if (!reg_info) - return -EINVAL; - - reg = reg_info->reg; - bit = reg_info->bit; - - /* Safe to spinlock during a write. */ - ds1685_rtc_begin_ctrl_access(rtc, &flags); - tmp = rtc->read(rtc, reg); - rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit)))); - ds1685_rtc_end_ctrl_access(rtc, flags); - - return count; -} - -/** - * DS1685_RTC_SYSFS_CTRL_REG_RO - device_attribute for read-only register bit. - * @bit: bit to read. - */ -#define DS1685_RTC_SYSFS_CTRL_REG_RO(bit) \ - static DEVICE_ATTR(bit, S_IRUGO, \ - ds1685_rtc_sysfs_ctrl_regs_show, NULL) - -/** - * DS1685_RTC_SYSFS_CTRL_REG_RW - device_attribute for read-write register bit. - * @bit: bit to read or write. - */ -#define DS1685_RTC_SYSFS_CTRL_REG_RW(bit) \ - static DEVICE_ATTR(bit, S_IRUGO | S_IWUSR, \ - ds1685_rtc_sysfs_ctrl_regs_show, \ - ds1685_rtc_sysfs_ctrl_regs_store) - -/* - * Control Register A bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(uip); -DS1685_RTC_SYSFS_CTRL_REG_RW(dv2); -DS1685_RTC_SYSFS_CTRL_REG_RW(dv1); -DS1685_RTC_SYSFS_CTRL_REG_RO(dv0); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs3); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs2); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs1); -DS1685_RTC_SYSFS_CTRL_REG_RW(rs0); - -static struct attribute* -ds1685_rtc_sysfs_ctrla_attrs[] = { - &dev_attr_uip.attr, - &dev_attr_dv2.attr, - &dev_attr_dv1.attr, - &dev_attr_dv0.attr, - &dev_attr_rs3.attr, - &dev_attr_rs2.attr, - &dev_attr_rs1.attr, - &dev_attr_rs0.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrla_grp = { - .name = "ctrla", - .attrs = ds1685_rtc_sysfs_ctrla_attrs, -}; - - -/* - * Control Register B bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(set); -DS1685_RTC_SYSFS_CTRL_REG_RW(pie); -DS1685_RTC_SYSFS_CTRL_REG_RW(aie); -DS1685_RTC_SYSFS_CTRL_REG_RW(uie); -DS1685_RTC_SYSFS_CTRL_REG_RW(sqwe); -DS1685_RTC_SYSFS_CTRL_REG_RO(dm); -DS1685_RTC_SYSFS_CTRL_REG_RO(2412); -DS1685_RTC_SYSFS_CTRL_REG_RO(dse); - -static struct attribute* -ds1685_rtc_sysfs_ctrlb_attrs[] = { - &dev_attr_set.attr, - &dev_attr_pie.attr, - &dev_attr_aie.attr, - &dev_attr_uie.attr, - &dev_attr_sqwe.attr, - &dev_attr_dm.attr, - &dev_attr_2412.attr, - &dev_attr_dse.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrlb_grp = { - .name = "ctrlb", - .attrs = ds1685_rtc_sysfs_ctrlb_attrs, -}; - -/* - * Control Register C bits. - * - * Reading Control C clears these bits! Reading them individually can - * possibly cause an interrupt to be missed. Use the /proc interface - * to see all the bits in this register simultaneously. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(irqf); -DS1685_RTC_SYSFS_CTRL_REG_RO(pf); -DS1685_RTC_SYSFS_CTRL_REG_RO(af); -DS1685_RTC_SYSFS_CTRL_REG_RO(uf); - -static struct attribute* -ds1685_rtc_sysfs_ctrlc_attrs[] = { - &dev_attr_irqf.attr, - &dev_attr_pf.attr, - &dev_attr_af.attr, - &dev_attr_uf.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrlc_grp = { - .name = "ctrlc", - .attrs = ds1685_rtc_sysfs_ctrlc_attrs, -}; - -/* - * Control Register D bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(vrt); - -static struct attribute* -ds1685_rtc_sysfs_ctrld_attrs[] = { - &dev_attr_vrt.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrld_grp = { - .name = "ctrld", - .attrs = ds1685_rtc_sysfs_ctrld_attrs, -}; - -/* - * Control Register 4A bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RO(vrt2); -DS1685_RTC_SYSFS_CTRL_REG_RO(incr); -DS1685_RTC_SYSFS_CTRL_REG_RW(pab); -DS1685_RTC_SYSFS_CTRL_REG_RW(rf); -DS1685_RTC_SYSFS_CTRL_REG_RW(wf); -DS1685_RTC_SYSFS_CTRL_REG_RW(kf); -#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689) -DS1685_RTC_SYSFS_CTRL_REG_RO(bme); -#endif - -static struct attribute* -ds1685_rtc_sysfs_ctrl4a_attrs[] = { - &dev_attr_vrt2.attr, - &dev_attr_incr.attr, - &dev_attr_pab.attr, - &dev_attr_rf.attr, - &dev_attr_wf.attr, - &dev_attr_kf.attr, -#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689) - &dev_attr_bme.attr, -#endif - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrl4a_grp = { - .name = "ctrl4a", - .attrs = ds1685_rtc_sysfs_ctrl4a_attrs, -}; - -/* - * Control Register 4B bits. - */ -DS1685_RTC_SYSFS_CTRL_REG_RW(abe); -DS1685_RTC_SYSFS_CTRL_REG_RW(e32k); -DS1685_RTC_SYSFS_CTRL_REG_RO(cs); -DS1685_RTC_SYSFS_CTRL_REG_RW(rce); -DS1685_RTC_SYSFS_CTRL_REG_RW(prs); -DS1685_RTC_SYSFS_CTRL_REG_RW(rie); -DS1685_RTC_SYSFS_CTRL_REG_RW(wie); -DS1685_RTC_SYSFS_CTRL_REG_RW(kse); - -static struct attribute* -ds1685_rtc_sysfs_ctrl4b_attrs[] = { - &dev_attr_abe.attr, - &dev_attr_e32k.attr, - &dev_attr_cs.attr, - &dev_attr_rce.attr, - &dev_attr_prs.attr, - &dev_attr_rie.attr, - &dev_attr_wie.attr, - &dev_attr_kse.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_ctrl4b_grp = { - .name = "ctrl4b", - .attrs = ds1685_rtc_sysfs_ctrl4b_attrs, -}; - - -/** - * struct ds1685_rtc_ctrl_regs. - * @name: char pointer for the bit name. - * @reg: control register the bit is in. - * @bit: the bit's offset in the register. - */ -struct ds1685_rtc_time_regs { - const char *name; - const u8 reg; - const u8 mask; - const u8 min; - const u8 max; -}; - -/* - * Time/Date register lookup tables. - */ -static const struct ds1685_rtc_time_regs -ds1685_time_regs_bcd_table[] = { - { "seconds", RTC_SECS, RTC_SECS_BCD_MASK, 0, 59 }, - { "minutes", RTC_MINS, RTC_MINS_BCD_MASK, 0, 59 }, - { "hours", RTC_HRS, RTC_HRS_24_BCD_MASK, 0, 23 }, - { "wday", RTC_WDAY, RTC_WDAY_MASK, 1, 7 }, - { "mday", RTC_MDAY, RTC_MDAY_BCD_MASK, 1, 31 }, - { "month", RTC_MONTH, RTC_MONTH_BCD_MASK, 1, 12 }, - { "year", RTC_YEAR, RTC_YEAR_BCD_MASK, 0, 99 }, - { "century", RTC_CENTURY, RTC_CENTURY_MASK, 0, 99 }, - { "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BCD_MASK, 0, 59 }, - { "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BCD_MASK, 0, 59 }, - { "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BCD_MASK, 0, 23 }, - { "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 1, 31 }, - { NULL, 0, 0, 0, 0 }, -}; - -static const struct ds1685_rtc_time_regs -ds1685_time_regs_bin_table[] = { - { "seconds", RTC_SECS, RTC_SECS_BIN_MASK, 0x00, 0x3b }, - { "minutes", RTC_MINS, RTC_MINS_BIN_MASK, 0x00, 0x3b }, - { "hours", RTC_HRS, RTC_HRS_24_BIN_MASK, 0x00, 0x17 }, - { "wday", RTC_WDAY, RTC_WDAY_MASK, 0x01, 0x07 }, - { "mday", RTC_MDAY, RTC_MDAY_BIN_MASK, 0x01, 0x1f }, - { "month", RTC_MONTH, RTC_MONTH_BIN_MASK, 0x01, 0x0c }, - { "year", RTC_YEAR, RTC_YEAR_BIN_MASK, 0x00, 0x63 }, - { "century", RTC_CENTURY, RTC_CENTURY_MASK, 0x00, 0x63 }, - { "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BIN_MASK, 0x00, 0x3b }, - { "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BIN_MASK, 0x00, 0x3b }, - { "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BIN_MASK, 0x00, 0x17 }, - { "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 0x01, 0x1f }, - { NULL, 0, 0, 0x00, 0x00 }, -}; - -/** - * ds1685_rtc_sysfs_time_regs_bcd_lookup - time/date reg bit lookup function. - * @name: register bit to look up in ds1685_time_regs_bcd_table. - */ -static const struct ds1685_rtc_time_regs* -ds1685_rtc_sysfs_time_regs_lookup(const char *name, bool bcd_mode) -{ - const struct ds1685_rtc_time_regs *p; - - if (bcd_mode) - p = ds1685_time_regs_bcd_table; - else - p = ds1685_time_regs_bin_table; - - for (; p->name != NULL; ++p) - if (strcmp(p->name, name) == 0) - return p; - - return NULL; -} - -/** - * ds1685_rtc_sysfs_time_regs_show - reads a time/date register via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - */ -static ssize_t -ds1685_rtc_sysfs_time_regs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 tmp; - struct ds1685_priv *rtc = dev_get_drvdata(dev); - const struct ds1685_rtc_time_regs *bcd_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true); - const struct ds1685_rtc_time_regs *bin_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false); - - /* Make sure we actually matched something. */ - if (!bcd_reg_info || !bin_reg_info) - return -EINVAL; - - /* bcd_reg_info->reg == bin_reg_info->reg. */ - ds1685_rtc_begin_data_access(rtc); - tmp = rtc->read(rtc, bcd_reg_info->reg); - ds1685_rtc_end_data_access(rtc); - - tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask, - bin_reg_info->mask); - - return sprintf(buf, "%d\n", tmp); -} - -/** - * ds1685_rtc_sysfs_time_regs_store - writes a time/date register via sysfs. - * @dev: pointer to device structure. - * @attr: pointer to device_attribute structure. - * @buf: pointer to char array to hold the output. - * @count: number of bytes written. - */ -static ssize_t -ds1685_rtc_sysfs_time_regs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - long int val = 0; - struct ds1685_priv *rtc = dev_get_drvdata(dev); - const struct ds1685_rtc_time_regs *bcd_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true); - const struct ds1685_rtc_time_regs *bin_reg_info = - ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false); - - /* We only accept numbers. */ - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; - - /* Make sure we actually matched something. */ - if (!bcd_reg_info || !bin_reg_info) - return -EINVAL; - - /* Check for a valid range. */ - if (rtc->bcd_mode) { - if ((val < bcd_reg_info->min) || (val > bcd_reg_info->max)) - return -ERANGE; - } else { - if ((val < bin_reg_info->min) || (val > bin_reg_info->max)) - return -ERANGE; - } - - val = ds1685_rtc_bin2bcd(rtc, val, bin_reg_info->mask, - bcd_reg_info->mask); - - /* bcd_reg_info->reg == bin_reg_info->reg. */ - ds1685_rtc_begin_data_access(rtc); - rtc->write(rtc, bcd_reg_info->reg, val); - ds1685_rtc_end_data_access(rtc); - - return count; -} - -/** - * DS1685_RTC_SYSFS_REG_RW - device_attribute for a read-write time register. - * @reg: time/date register to read or write. - */ -#define DS1685_RTC_SYSFS_TIME_REG_RW(reg) \ - static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, \ - ds1685_rtc_sysfs_time_regs_show, \ - ds1685_rtc_sysfs_time_regs_store) - -/* - * Time/Date Register bits. - */ -DS1685_RTC_SYSFS_TIME_REG_RW(seconds); -DS1685_RTC_SYSFS_TIME_REG_RW(minutes); -DS1685_RTC_SYSFS_TIME_REG_RW(hours); -DS1685_RTC_SYSFS_TIME_REG_RW(wday); -DS1685_RTC_SYSFS_TIME_REG_RW(mday); -DS1685_RTC_SYSFS_TIME_REG_RW(month); -DS1685_RTC_SYSFS_TIME_REG_RW(year); -DS1685_RTC_SYSFS_TIME_REG_RW(century); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_seconds); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_minutes); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_hours); -DS1685_RTC_SYSFS_TIME_REG_RW(alarm_mday); - -static struct attribute* -ds1685_rtc_sysfs_time_attrs[] = { - &dev_attr_seconds.attr, - &dev_attr_minutes.attr, - &dev_attr_hours.attr, - &dev_attr_wday.attr, - &dev_attr_mday.attr, - &dev_attr_month.attr, - &dev_attr_year.attr, - &dev_attr_century.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_time_grp = { - .name = "datetime", - .attrs = ds1685_rtc_sysfs_time_attrs, -}; - -static struct attribute* -ds1685_rtc_sysfs_alarm_attrs[] = { - &dev_attr_alarm_seconds.attr, - &dev_attr_alarm_minutes.attr, - &dev_attr_alarm_hours.attr, - &dev_attr_alarm_mday.attr, - NULL, -}; - -static const struct attribute_group -ds1685_rtc_sysfs_alarm_grp = { - .name = "alarm", - .attrs = ds1685_rtc_sysfs_alarm_attrs, -}; -#endif /* CONFIG_RTC_DS1685_SYSFS_REGS */ - - /** * ds1685_rtc_sysfs_register - register sysfs files. * @dev: pointer to device structure. @@ -1752,39 +1206,6 @@ ds1685_rtc_sysfs_register(struct device *dev) if (ret) return ret; -#ifdef CONFIG_RTC_DS1685_SYSFS_REGS - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp); - if (ret) - return ret; - - ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp); - if (ret) - return ret; -#endif return 0; } @@ -1798,17 +1219,6 @@ ds1685_rtc_sysfs_unregister(struct device *dev) sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr); sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp); -#ifdef CONFIG_RTC_DS1685_SYSFS_REGS - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp); - sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp); -#endif - return 0; } #endif /* CONFIG_SYSFS */ diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 1a2c38cc0178..ea18a8f4bce0 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -14,6 +14,8 @@ #include <linux/i2c.h> #include <linux/bcd.h> #include <linux/rtc.h> +#include "rtc-core.h" +#include <linux/of_irq.h> /* Register map */ /* rtc section */ @@ -33,13 +35,16 @@ #define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ #define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ #define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ +#define ISL1208_REG_SR_EVT (1<<3) /* event */ #define ISL1208_REG_SR_ALM (1<<2) /* alarm */ #define ISL1208_REG_SR_BAT (1<<1) /* battery */ #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ #define ISL1208_REG_INT 0x08 #define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */ #define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */ -#define ISL1208_REG_09 0x09 /* reserved */ +#define ISL1219_REG_EV 0x09 +#define ISL1219_REG_EV_EVEN (1<<4) /* event detection enable */ +#define ISL1219_REG_EV_EVIENB (1<<7) /* event in pull-up disable */ #define ISL1208_REG_ATR 0x0a #define ISL1208_REG_DTR 0x0b @@ -57,8 +62,24 @@ #define ISL1208_REG_USR2 0x13 #define ISL1208_USR_SECTION_LEN 2 +/* event section */ +#define ISL1219_REG_SCT 0x14 +#define ISL1219_REG_MNT 0x15 +#define ISL1219_REG_HRT 0x16 +#define ISL1219_REG_DTT 0x17 +#define ISL1219_REG_MOT 0x18 +#define ISL1219_REG_YRT 0x19 +#define ISL1219_EVT_SECTION_LEN 6 + static struct i2c_driver isl1208_driver; +/* ISL1208 various variants */ +enum { + TYPE_ISL1208 = 0, + TYPE_ISL1218, + TYPE_ISL1219, +}; + /* block read */ static int isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], @@ -80,8 +101,8 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], }; int ret; - BUG_ON(reg > ISL1208_REG_USR2); - BUG_ON(reg + len > ISL1208_REG_USR2 + 1); + WARN_ON(reg > ISL1219_REG_YRT); + WARN_ON(reg + len > ISL1219_REG_YRT + 1); ret = i2c_transfer(client->adapter, msgs, 2); if (ret > 0) @@ -104,8 +125,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], }; int ret; - BUG_ON(reg > ISL1208_REG_USR2); - BUG_ON(reg + len > ISL1208_REG_USR2 + 1); + WARN_ON(reg > ISL1219_REG_YRT); + WARN_ON(reg + len > ISL1219_REG_YRT + 1); i2c_buf[0] = reg; memcpy(&i2c_buf[1], &buf[0], len); @@ -493,6 +514,73 @@ isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm); } +static ssize_t timestamp0_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = dev_get_drvdata(dev); + int sr; + + sr = isl1208_i2c_get_sr(client); + if (sr < 0) { + dev_err(dev, "%s: reading SR failed\n", __func__); + return sr; + } + + sr &= ~ISL1208_REG_SR_EVT; + + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); + if (sr < 0) + dev_err(dev, "%s: writing SR failed\n", + __func__); + + return count; +}; + +static ssize_t timestamp0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = dev_get_drvdata(dev); + u8 regs[ISL1219_EVT_SECTION_LEN] = { 0, }; + struct rtc_time tm; + int sr; + + sr = isl1208_i2c_get_sr(client); + if (sr < 0) { + dev_err(dev, "%s: reading SR failed\n", __func__); + return sr; + } + + if (!(sr & ISL1208_REG_SR_EVT)) + return 0; + + sr = isl1208_i2c_read_regs(client, ISL1219_REG_SCT, regs, + ISL1219_EVT_SECTION_LEN); + if (sr < 0) { + dev_err(dev, "%s: reading event section failed\n", + __func__); + return 0; + } + + /* MSB of each alarm register is an enable bit */ + tm.tm_sec = bcd2bin(regs[ISL1219_REG_SCT - ISL1219_REG_SCT] & 0x7f); + tm.tm_min = bcd2bin(regs[ISL1219_REG_MNT - ISL1219_REG_SCT] & 0x7f); + tm.tm_hour = bcd2bin(regs[ISL1219_REG_HRT - ISL1219_REG_SCT] & 0x3f); + tm.tm_mday = bcd2bin(regs[ISL1219_REG_DTT - ISL1219_REG_SCT] & 0x3f); + tm.tm_mon = + bcd2bin(regs[ISL1219_REG_MOT - ISL1219_REG_SCT] & 0x1f) - 1; + tm.tm_year = bcd2bin(regs[ISL1219_REG_YRT - ISL1219_REG_SCT]) + 100; + + sr = rtc_valid_tm(&tm); + if (sr) + return sr; + + return sprintf(buf, "%llu\n", + (unsigned long long)rtc_tm_to_time64(&tm)); +}; + +static DEVICE_ATTR_RW(timestamp0); + static irqreturn_t isl1208_rtc_interrupt(int irq, void *data) { @@ -538,6 +626,13 @@ isl1208_rtc_interrupt(int irq, void *data) return err; } + if (sr & ISL1208_REG_SR_EVT) { + sysfs_notify(&rtc->dev.kobj, NULL, + dev_attr_timestamp0.attr.name); + dev_warn(&client->dev, "event detected"); + handled = 1; + } + return handled ? IRQ_HANDLED : IRQ_NONE; } @@ -623,11 +718,39 @@ static const struct attribute_group isl1208_rtc_sysfs_files = { .attrs = isl1208_rtc_attrs, }; +static struct attribute *isl1219_rtc_attrs[] = { + &dev_attr_timestamp0.attr, + NULL +}; + +static const struct attribute_group isl1219_rtc_sysfs_files = { + .attrs = isl1219_rtc_attrs, +}; + +static int isl1208_setup_irq(struct i2c_client *client, int irq) +{ + int rc = devm_request_threaded_irq(&client->dev, irq, NULL, + isl1208_rtc_interrupt, + IRQF_SHARED | IRQF_ONESHOT, + isl1208_driver.driver.name, + client); + if (!rc) { + device_init_wakeup(&client->dev, 1); + enable_irq_wake(irq); + } else { + dev_err(&client->dev, + "Unable to request irq %d, no alarm support\n", + irq); + } + return rc; +} + static int isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; struct rtc_device *rtc; + int evdet_irq = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -642,6 +765,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) rtc->ops = &isl1208_rtc_ops; i2c_set_clientdata(client, rtc); + dev_set_drvdata(&rtc->dev, client); rc = isl1208_i2c_get_sr(client); if (rc < 0) { @@ -653,26 +777,46 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_warn(&client->dev, "rtc power failure detected, " "please set clock.\n"); + if (id->driver_data == TYPE_ISL1219) { + struct device_node *np = client->dev.of_node; + u32 evienb; + + rc = i2c_smbus_read_byte_data(client, ISL1219_REG_EV); + if (rc < 0) { + dev_err(&client->dev, "failed to read EV reg\n"); + return rc; + } + rc |= ISL1219_REG_EV_EVEN; + if (!of_property_read_u32(np, "isil,ev-evienb", &evienb)) { + if (evienb) + rc |= ISL1219_REG_EV_EVIENB; + else + rc &= ~ISL1219_REG_EV_EVIENB; + } + rc = i2c_smbus_write_byte_data(client, ISL1219_REG_EV, rc); + if (rc < 0) { + dev_err(&client->dev, "could not enable tamper detection\n"); + return rc; + } + rc = rtc_add_group(rtc, &isl1219_rtc_sysfs_files); + if (rc) + return rc; + evdet_irq = of_irq_get_byname(np, "evdet"); + } + rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); if (rc) return rc; - if (client->irq > 0) { - rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, - isl1208_rtc_interrupt, - IRQF_SHARED | IRQF_ONESHOT, - isl1208_driver.driver.name, - client); - if (!rc) { - device_init_wakeup(&client->dev, 1); - enable_irq_wake(client->irq); - } else { - dev_err(&client->dev, - "Unable to request irq %d, no alarm support\n", - client->irq); - client->irq = 0; - } - } + if (client->irq > 0) + rc = isl1208_setup_irq(client, client->irq); + if (rc) + return rc; + + if (evdet_irq > 0 && evdet_irq != client->irq) + rc = isl1208_setup_irq(client, evdet_irq); + if (rc) + return rc; return rtc_register_device(rtc); } @@ -686,8 +830,9 @@ isl1208_remove(struct i2c_client *client) } static const struct i2c_device_id isl1208_id[] = { - { "isl1208", 0 }, - { "isl1218", 0 }, + { "isl1208", TYPE_ISL1208 }, + { "isl1218", TYPE_ISL1218 }, + { "isl1219", TYPE_ISL1219 }, { } }; MODULE_DEVICE_TABLE(i2c, isl1208_id); @@ -695,6 +840,7 @@ MODULE_DEVICE_TABLE(i2c, isl1208_id); static const struct of_device_id isl1208_of_match[] = { { .compatible = "isil,isl1208" }, { .compatible = "isil,isl1218" }, + { .compatible = "isil,isl1219" }, { } }; MODULE_DEVICE_TABLE(of, isl1208_of_match); diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 1053a406b3aa..ac9ca1042889 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -373,7 +373,6 @@ static int m48t59_rtc_probe(struct platform_device *pdev) struct m48t59_private *m48t59 = NULL; struct resource *res; int ret = -ENOMEM; - char *name; const struct rtc_class_ops *ops; struct nvmem_config nvmem_cfg = { .name = "m48t59-", @@ -448,17 +447,14 @@ static int m48t59_rtc_probe(struct platform_device *pdev) } switch (pdata->type) { case M48T59RTC_TYPE_M48T59: - name = "m48t59"; ops = &m48t59_rtc_ops; pdata->offset = 0x1ff0; break; case M48T59RTC_TYPE_M48T02: - name = "m48t02"; ops = &m48t02_rtc_ops; pdata->offset = 0x7f0; break; case M48T59RTC_TYPE_M48T08: - name = "m48t08"; ops = &m48t02_rtc_ops; pdata->offset = 0x1ff0; break; diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index cefde273fae6..8a60900d6b8b 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -1,16 +1,10 @@ -/* - * RTC driver for Maxim MAX77686 and MAX77802 - * - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * - * based on rtc-max8997.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// RTC driver for Maxim MAX77686 and MAX77802 +// +// Copyright (C) 2012 Samsung Electronics Co.Ltd +// +// based on rtc-max8997.c #include <linux/i2c.h> #include <linux/slab.h> diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index e8cee123e8aa..08c661a332ec 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -1,16 +1,10 @@ -/* - * RTC driver for Maxim MAX8997 - * - * Copyright (C) 2013 Samsung Electronics Co.Ltd - * - * based on rtc-max8998.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// RTC driver for Maxim MAX8997 +// +// Copyright (C) 2013 Samsung Electronics Co.Ltd +// +// based on rtc-max8998.c #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index d8c0f9b3f87d..c873b4509b3c 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -1,16 +1,10 @@ -/* - * RTC driver for Maxim MAX8998 - * - * Copyright (C) 2010 Samsung Electronics Co.Ltd - * Author: Minkyu Kang <mk7.kang@samsung.com> - * Author: Joonyoung Shim <jy0922.shim@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// RTC driver for Maxim MAX8998 +// +// Copyright (C) 2010 Samsung Electronics Co.Ltd +// Author: Minkyu Kang <mk7.kang@samsung.com> +// Author: Joonyoung Shim <jy0922.shim@samsung.com> #include <linux/module.h> #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 39086398833e..323ff55cc165 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -449,6 +449,7 @@ static void omap_rtc_power_off(void) if (tm2bcd(&tm) < 0) { dev_err(&rtc->rtc->dev, "power off failed\n"); + rtc->type->lock(rtc); return; } @@ -582,9 +583,7 @@ static int rtc_pinconf_get(struct pinctrl_dev *pctldev, u32 val; u16 arg = 0; - rtc->type->unlock(rtc); val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); - rtc->type->lock(rtc); switch (param) { case PIN_CONFIG_INPUT_ENABLE: @@ -614,9 +613,7 @@ static int rtc_pinconf_set(struct pinctrl_dev *pctldev, u32 param_val; int i; - rtc->type->unlock(rtc); val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); - rtc->type->lock(rtc); /* active low by default */ val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin); @@ -861,13 +858,6 @@ static int omap_rtc_probe(struct platform_device *pdev) goto err; } - if (rtc->is_pmic_controller) { - if (!pm_power_off) { - omap_rtc_power_off_rtc = rtc; - pm_power_off = omap_rtc_power_off; - } - } - /* Support ext_wakeup pinconf */ rtc_pinctrl_desc.name = dev_name(&pdev->dev); @@ -880,12 +870,21 @@ static int omap_rtc_probe(struct platform_device *pdev) ret = rtc_register_device(rtc->rtc); if (ret) - goto err; + goto err_deregister_pinctrl; rtc_nvmem_register(rtc->rtc, &omap_rtc_nvmem_config); + if (rtc->is_pmic_controller) { + if (!pm_power_off) { + omap_rtc_power_off_rtc = rtc; + pm_power_off = omap_rtc_power_off; + } + } + return 0; +err_deregister_pinctrl: + pinctrl_unregister(rtc->pctldev); err: clk_disable_unprepare(rtc->clk); device_init_wakeup(&pdev->dev, false); diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index e83be1852c2f..9f99a0966550 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -36,6 +36,11 @@ #define PCF2127_REG_MO (0x08) #define PCF2127_REG_YR (0x09) +/* the pcf2127 has 512 bytes nvmem, pcf2129 doesn't */ +#define PCF2127_REG_RAM_addr_MSB 0x1a +#define PCF2127_REG_RAM_wrt_cmd 0x1c +#define PCF2127_REG_RAM_rd_cmd 0x1d + #define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ struct pcf2127 { @@ -183,10 +188,47 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { .set_time = pcf2127_rtc_set_time, }; +static int pcf2127_nvmem_read(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct pcf2127 *pcf2127 = priv; + int ret; + unsigned char offsetbuf[] = { offset >> 8, offset }; + + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, + offsetbuf, 2); + if (ret) + return ret; + + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_rd_cmd, + val, bytes); + + return ret ?: bytes; +} + +static int pcf2127_nvmem_write(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + struct pcf2127 *pcf2127 = priv; + int ret; + unsigned char offsetbuf[] = { offset >> 8, offset }; + + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, + offsetbuf, 2); + if (ret) + return ret; + + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_wrt_cmd, + val, bytes); + + return ret ?: bytes; +} + static int pcf2127_probe(struct device *dev, struct regmap *regmap, - const char *name) + const char *name, bool has_nvmem) { struct pcf2127 *pcf2127; + int ret = 0; dev_dbg(dev, "%s\n", __func__); @@ -200,8 +242,21 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops, THIS_MODULE); + if (IS_ERR(pcf2127->rtc)) + return PTR_ERR(pcf2127->rtc); + + if (has_nvmem) { + struct nvmem_config nvmem_cfg = { + .priv = pcf2127, + .reg_read = pcf2127_nvmem_read, + .reg_write = pcf2127_nvmem_write, + .size = 512, + }; + + ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); + } - return PTR_ERR_OR_ZERO(pcf2127->rtc); + return ret; } #ifdef CONFIG_OF @@ -309,11 +364,11 @@ static int pcf2127_i2c_probe(struct i2c_client *client, } return pcf2127_probe(&client->dev, regmap, - pcf2127_i2c_driver.driver.name); + pcf2127_i2c_driver.driver.name, id->driver_data); } static const struct i2c_device_id pcf2127_i2c_id[] = { - { "pcf2127", 0 }, + { "pcf2127", 1 }, { "pcf2129", 0 }, { } }; @@ -372,11 +427,12 @@ static int pcf2127_spi_probe(struct spi_device *spi) return PTR_ERR(regmap); } - return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name); + return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name, + spi_get_device_id(spi)->driver_data); } static const struct spi_device_id pcf2127_spi_id[] = { - { "pcf2127", 0 }, + { "pcf2127", 1 }, { "pcf2129", 0 }, { } }; diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 49bcbb3d4a69..283c2335b01b 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -43,37 +43,38 @@ static struct i2c_driver pcf85063_driver; static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) { - s32 ret; + int rc; + u8 reg; - ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); - if (ret < 0) { + rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); + if (rc < 0) { dev_err(&client->dev, "Failing to stop the clock\n"); return -EIO; } /* stop the clock */ - ret |= PCF85063_REG_CTRL1_STOP; + reg = rc | PCF85063_REG_CTRL1_STOP; - ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret); - if (ret < 0) { + rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg); + if (rc < 0) { dev_err(&client->dev, "Failing to stop the clock\n"); return -EIO; } - *ctrl1 = ret; + *ctrl1 = reg; return 0; } static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1) { - s32 ret; + int rc; /* start the clock */ ctrl1 &= ~PCF85063_REG_CTRL1_STOP; - ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1); - if (ret < 0) { + rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1); + if (rc < 0) { dev_err(&client->dev, "Failing to start the clock\n"); return -EIO; } diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 8428455432ca..6495f84f7428 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -1,19 +1,9 @@ -/* - * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd - * http://www.samsung.com - * - * Copyright (C) 2013 Google, Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2013-2014 Samsung Electronics Co., Ltd +// http://www.samsung.com +// +// Copyright (C) 2013 Google, Inc #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index ed71d1113627..304d905cb23f 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -224,7 +224,6 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) info->rtc = rtc; rtc->max_user_freq = RTC_FREQ; - rtc_irq_set_freq(rtc, NULL, RTC_FREQ); /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 776b70a14e03..51ba414798a8 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -143,8 +143,6 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc) static int __sh_rtc_periodic(struct sh_rtc *rtc) { - struct rtc_device *rtc_dev = rtc->rtc_dev; - struct rtc_task *irq_task; unsigned int tmp, pending; tmp = readb(rtc->regbase + RCR2); @@ -161,14 +159,7 @@ static int __sh_rtc_periodic(struct sh_rtc *rtc) else { if (rtc->periodic_freq & PF_HP) rtc->periodic_freq |= PF_COUNT; - if (rtc->periodic_freq & PF_KOU) { - spin_lock(&rtc_dev->irq_task_lock); - irq_task = rtc_dev->irq_task; - if (irq_task) - irq_task->func(irq_task->private_data); - spin_unlock(&rtc_dev->irq_task_lock); - } else - rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); } return pending; @@ -224,81 +215,6 @@ static irqreturn_t sh_rtc_shared(int irq, void *dev_id) return IRQ_RETVAL(ret); } -static int sh_rtc_irq_set_state(struct device *dev, int enable) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int tmp; - - spin_lock_irq(&rtc->lock); - - tmp = readb(rtc->regbase + RCR2); - - if (enable) { - rtc->periodic_freq |= PF_KOU; - tmp &= ~RCR2_PEF; /* Clear PES bit */ - tmp |= (rtc->periodic_freq & ~PF_HP); /* Set PES2-0 */ - } else { - rtc->periodic_freq &= ~PF_KOU; - tmp &= ~(RCR2_PESMASK | RCR2_PEF); - } - - writeb(tmp, rtc->regbase + RCR2); - - spin_unlock_irq(&rtc->lock); - - return 0; -} - -static int sh_rtc_irq_set_freq(struct device *dev, int freq) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - int tmp, ret = 0; - - spin_lock_irq(&rtc->lock); - tmp = rtc->periodic_freq & PF_MASK; - - switch (freq) { - case 0: - rtc->periodic_freq = 0x00; - break; - case 1: - rtc->periodic_freq = 0x60; - break; - case 2: - rtc->periodic_freq = 0x50; - break; - case 4: - rtc->periodic_freq = 0x40; - break; - case 8: - rtc->periodic_freq = 0x30 | PF_HP; - break; - case 16: - rtc->periodic_freq = 0x30; - break; - case 32: - rtc->periodic_freq = 0x20 | PF_HP; - break; - case 64: - rtc->periodic_freq = 0x20; - break; - case 128: - rtc->periodic_freq = 0x10 | PF_HP; - break; - case 256: - rtc->periodic_freq = 0x10; - break; - default: - ret = -ENOTSUPP; - } - - if (ret == 0) - rtc->periodic_freq |= tmp; - - spin_unlock_irq(&rtc->lock); - return ret; -} - static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) { struct sh_rtc *rtc = dev_get_drvdata(dev); @@ -675,8 +591,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); /* everything disabled by default */ - sh_rtc_irq_set_freq(&pdev->dev, 0); - sh_rtc_irq_set_state(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); sh_rtc_setcie(&pdev->dev, 0); @@ -708,8 +622,6 @@ static int __exit sh_rtc_remove(struct platform_device *pdev) { struct sh_rtc *rtc = platform_get_drvdata(pdev); - sh_rtc_irq_set_state(&pdev->dev, 0); - sh_rtc_setaie(&pdev->dev, 0); sh_rtc_setcie(&pdev->dev, 0); diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 8a75cc3af6e7..b2483a749ac4 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -40,49 +40,83 @@ struct snvs_rtc_data { struct clk *clk; }; +/* Read 64 bit timer register, which could be in inconsistent state */ +static u64 rtc_read_lpsrt(struct snvs_rtc_data *data) +{ + u32 msb, lsb; + + regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &msb); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &lsb); + return (u64)msb << 32 | lsb; +} + +/* Read the secure real time counter, taking care to deal with the cases of the + * counter updating while being read. + */ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) { u64 read1, read2; - u32 val; + unsigned int timeout = 100; + /* As expected, the registers might update between the read of the LSB + * reg and the MSB reg. It's also possible that one register might be + * in partially modified state as well. + */ + read1 = rtc_read_lpsrt(data); do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); - read1 = val; - read1 <<= 32; - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); - read1 |= val; - - regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); - read2 = val; - read2 <<= 32; - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); - read2 |= val; - } while (read1 != read2); + read2 = read1; + read1 = rtc_read_lpsrt(data); + } while (read1 != read2 && --timeout); + if (!timeout) + dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); /* Convert 47-bit counter to 32-bit raw second count */ return (u32) (read1 >> CNTR_TO_SECS_SH); } -static void rtc_write_sync_lp(struct snvs_rtc_data *data) +/* Just read the lsb from the counter, dealing with inconsistent state */ +static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb) +{ + u32 count1, count2; + unsigned int timeout = 100; + + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); + do { + count2 = count1; + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); + } while (count1 != count2 && --timeout); + if (!timeout) { + dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n"); + return -ETIMEDOUT; + } + + *lsb = count1; + return 0; +} + +static int rtc_write_sync_lp(struct snvs_rtc_data *data) { - u32 count1, count2, count3; - int i; - - /* Wait for 3 CKIL cycles */ - for (i = 0; i < 3; i++) { - do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); - } while (count1 != count2); - - /* Now wait until counter value changes */ - do { - do { - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); - regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3); - } while (count2 != count3); - } while (count3 == count1); + u32 count1, count2; + u32 elapsed; + unsigned int timeout = 1000; + int ret; + + ret = rtc_read_lp_counter_lsb(data, &count1); + if (ret) + return ret; + + /* Wait for 3 CKIL cycles, about 61.0-91.5 µs */ + do { + ret = rtc_read_lp_counter_lsb(data, &count2); + if (ret) + return ret; + elapsed = count2 - count1; /* wrap around _is_ handled! */ + } while (elapsed < 3 && --timeout); + if (!timeout) { + dev_err(&data->rtc->dev, "Timeout waiting for LPSRT Counter to change\n"); + return -ETIMEDOUT; } + return 0; } static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) @@ -166,9 +200,7 @@ static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN), enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0); - rtc_write_sync_lp(data); - - return 0; + return rtc_write_sync_lp(data); } static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -176,11 +208,14 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct snvs_rtc_data *data = dev_get_drvdata(dev); struct rtc_time *alrm_tm = &alrm->time; unsigned long time; + int ret; rtc_tm_to_time(alrm_tm, &time); regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); - rtc_write_sync_lp(data); + ret = rtc_write_sync_lp(data); + if (ret) + return ret; regmap_write(data->regmap, data->offset + SNVS_LPTAR, time); /* Clear alarm interrupt status bit */ diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index d578e40d5a50..b76318fd5bb0 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -288,10 +288,22 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc_data); - err = stmp_reset_block(rtc_data->io); - if (err) { - dev_err(&pdev->dev, "stmp_reset_block failed: %d\n", err); - return err; + /* + * Resetting the rtc stops the watchdog timer that is potentially + * running. So (assuming it is running on purpose) don't reset if the + * watchdog is enabled. + */ + if (readl(rtc_data->io + STMP3XXX_RTC_CTRL) & + STMP3XXX_RTC_CTRL_WATCHDOGEN) { + dev_info(&pdev->dev, + "Watchdog is running, skip resetting rtc\n"); + } else { + err = stmp_reset_block(rtc_data->io); + if (err) { + dev_err(&pdev->dev, "stmp_reset_block failed: %d\n", + err); + return err; + } } /* diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 454da38c6012..f1ff30ade534 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -317,3 +317,46 @@ const struct attribute_group **rtc_get_dev_attribute_groups(void) { return rtc_attr_groups; } + +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) +{ + size_t old_cnt = 0, add_cnt = 0, new_cnt; + const struct attribute_group **groups, **old; + + if (rtc->registered) + return -EINVAL; + if (!grps) + return -EINVAL; + + groups = rtc->dev.groups; + if (groups) + for (; *groups; groups++) + old_cnt++; + + for (groups = grps; *groups; groups++) + add_cnt++; + + new_cnt = old_cnt + add_cnt + 1; + groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL); + if (IS_ERR_OR_NULL(groups)) + return PTR_ERR(groups); + memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups)); + memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups)); + groups[old_cnt + add_cnt] = NULL; + + old = rtc->dev.groups; + rtc->dev.groups = groups; + if (old && old != rtc_attr_groups) + devm_kfree(&rtc->dev, old); + + return 0; +} +EXPORT_SYMBOL(rtc_add_groups); + +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) +{ + const struct attribute_group *groups[] = { grp, NULL }; + + return rtc_add_groups(rtc, groups); +} +EXPORT_SYMBOL(rtc_add_group); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 8469256edc2a..ade6a82709be 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -22,7 +22,7 @@ struct rtc_test_data { bool alarm_en; }; -struct platform_device *pdev[MAX_RTC_TEST]; +static struct platform_device *pdev[MAX_RTC_TEST]; static int test_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index ed607288e696..23e526cda5c1 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -922,9 +922,11 @@ __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff, unsigned long dev_sz; dev_sz = dev_info->end - dev_info->start + 1; - *kaddr = (void *) dev_info->start + offset; - *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), - PFN_DEV|PFN_SPECIAL); + if (kaddr) + *kaddr = (void *) dev_info->start + offset; + if (pfn) + *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), + PFN_DEV|PFN_SPECIAL); return (dev_sz - offset) / PAGE_SIZE; } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index bf27fc4d1335..ec891bc7d10a 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -34,6 +34,7 @@ #include <linux/crypto.h> #include <linux/mod_devicetable.h> #include <linux/debugfs.h> +#include <linux/ctype.h> #include "ap_bus.h" #include "ap_debug.h" @@ -43,19 +44,34 @@ */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */ static DEFINE_SPINLOCK(ap_domain_lock); -module_param_named(domain, ap_domain_index, int, S_IRUSR|S_IRGRP); +module_param_named(domain, ap_domain_index, int, 0440); MODULE_PARM_DESC(domain, "domain index for ap devices"); EXPORT_SYMBOL(ap_domain_index); -static int ap_thread_flag = 0; -module_param_named(poll_thread, ap_thread_flag, int, S_IRUSR|S_IRGRP); +static int ap_thread_flag; +module_param_named(poll_thread, ap_thread_flag, int, 0440); MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); +static char *apm_str; +module_param_named(apmask, apm_str, charp, 0440); +MODULE_PARM_DESC(apmask, "AP bus adapter mask."); + +static char *aqm_str; +module_param_named(aqmask, aqm_str, charp, 0440); +MODULE_PARM_DESC(aqmask, "AP bus domain mask."); + static struct device *ap_root_device; DEFINE_SPINLOCK(ap_list_lock); LIST_HEAD(ap_card_list); +/* Default permissions (card and domain masking) */ +static struct ap_perms { + DECLARE_BITMAP(apm, AP_DEVICES); + DECLARE_BITMAP(aqm, AP_DOMAINS); +} ap_perms; +static DEFINE_MUTEX(ap_perms_mutex); + static struct ap_config_info *ap_configuration; static bool initialised; @@ -78,22 +94,26 @@ static DECLARE_WORK(ap_scan_work, ap_scan_bus); static void ap_tasklet_fn(unsigned long); static DECLARE_TASKLET(ap_tasklet, ap_tasklet_fn, 0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); -static struct task_struct *ap_poll_kthread = NULL; +static struct task_struct *ap_poll_kthread; static DEFINE_MUTEX(ap_poll_thread_mutex); static DEFINE_SPINLOCK(ap_poll_timer_lock); static struct hrtimer ap_poll_timer; -/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. - * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ +/* + * In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. + * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling. + */ static unsigned long long poll_timeout = 250000; /* Suspend flag */ static int ap_suspend_flag; /* Maximum domain id */ static int ap_max_domain_id; -/* Flag to check if domain was set through module parameter domain=. This is +/* + * Flag to check if domain was set through module parameter domain=. This is * important when supsend and resume is done in a z/VM environment where the - * domain might change. */ -static int user_set_domain = 0; + * domain might change. + */ +static int user_set_domain; static struct bus_type ap_bus_type; /* Adapter interrupt definitions */ @@ -531,7 +551,7 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * It sets up a single environment variable DEV_TYPE which contains the * hardware device type. */ -static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) +static int ap_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ap_device *ap_dev = to_ap_dev(dev); int retval = 0; @@ -570,7 +590,7 @@ static int ap_dev_resume(struct device *dev) static void ap_bus_suspend(void) { - AP_DBF(DBF_DEBUG, "ap_bus_suspend running\n"); + AP_DBF(DBF_DEBUG, "%s running\n", __func__); ap_suspend_flag = 1; /* @@ -607,7 +627,7 @@ static void ap_bus_resume(void) { int rc; - AP_DBF(DBF_DEBUG, "ap_bus_resume running\n"); + AP_DBF(DBF_DEBUG, "%s running\n", __func__); /* remove all queue devices */ bus_for_each_dev(&ap_bus_type, NULL, NULL, @@ -666,11 +686,97 @@ static struct bus_type ap_bus_type = { .pm = &ap_bus_pm_ops, }; +static int __ap_revise_reserved(struct device *dev, void *dummy) +{ + int rc, card, queue, devres, drvres; + + if (is_queue_dev(dev)) { + card = AP_QID_CARD(to_ap_queue(dev)->qid); + queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); + mutex_lock(&ap_perms_mutex); + devres = test_bit_inv(card, ap_perms.apm) + && test_bit_inv(queue, ap_perms.aqm); + mutex_unlock(&ap_perms_mutex); + drvres = to_ap_drv(dev->driver)->flags + & AP_DRIVER_FLAG_DEFAULT; + if (!!devres != !!drvres) { + AP_DBF(DBF_DEBUG, "reprobing queue=%02x.%04x\n", + card, queue); + rc = device_reprobe(dev); + } + } + + return 0; +} + +static void ap_bus_revise_bindings(void) +{ + bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_revise_reserved); +} + +int ap_owned_by_def_drv(int card, int queue) +{ + int rc = 0; + + if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >= AP_DOMAINS) + return -EINVAL; + + mutex_lock(&ap_perms_mutex); + + if (test_bit_inv(card, ap_perms.apm) + && test_bit_inv(queue, ap_perms.aqm)) + rc = 1; + + mutex_unlock(&ap_perms_mutex); + + return rc; +} +EXPORT_SYMBOL(ap_owned_by_def_drv); + +int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, + unsigned long *aqm) +{ + int card, queue, rc = 0; + + mutex_lock(&ap_perms_mutex); + + for (card = 0; !rc && card < AP_DEVICES; card++) + if (test_bit_inv(card, apm) && + test_bit_inv(card, ap_perms.apm)) + for (queue = 0; !rc && queue < AP_DOMAINS; queue++) + if (test_bit_inv(queue, aqm) && + test_bit_inv(queue, ap_perms.aqm)) + rc = 1; + + mutex_unlock(&ap_perms_mutex); + + return rc; +} +EXPORT_SYMBOL(ap_apqn_in_matrix_owned_by_def_drv); + static int ap_device_probe(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = to_ap_drv(dev->driver); - int rc; + int card, queue, devres, drvres, rc; + + if (is_queue_dev(dev)) { + /* + * If the apqn is marked as reserved/used by ap bus and + * default drivers, only probe with drivers with the default + * flag set. If it is not marked, only probe with drivers + * with the default flag not set. + */ + card = AP_QID_CARD(to_ap_queue(dev)->qid); + queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); + mutex_lock(&ap_perms_mutex); + devres = test_bit_inv(card, ap_perms.apm) + && test_bit_inv(queue, ap_perms.aqm); + mutex_unlock(&ap_perms_mutex); + drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT; + if (!!devres != !!drvres) + return -ENODEV; + } /* Add queue/card to list of active queues/cards */ spin_lock_bh(&ap_list_lock); @@ -751,8 +857,163 @@ void ap_bus_force_rescan(void) EXPORT_SYMBOL(ap_bus_force_rescan); /* + * hex2bitmap() - parse hex mask string and set bitmap. + * Valid strings are "0x012345678" with at least one valid hex number. + * Rest of the bitmap to the right is padded with 0. No spaces allowed + * within the string, the leading 0x may be omitted. + * Returns the bitmask with exactly the bits set as given by the hex + * string (both in big endian order). + */ +static int hex2bitmap(const char *str, unsigned long *bitmap, int bits) +{ + int i, n, b; + + /* bits needs to be a multiple of 8 */ + if (bits & 0x07) + return -EINVAL; + + memset(bitmap, 0, bits / 8); + + if (str[0] == '0' && str[1] == 'x') + str++; + if (*str == 'x') + str++; + + for (i = 0; isxdigit(*str) && i < bits; str++) { + b = hex_to_bin(*str); + for (n = 0; n < 4; n++) + if (b & (0x08 >> n)) + set_bit_inv(i + n, bitmap); + i += 4; + } + + if (*str == '\n') + str++; + if (*str) + return -EINVAL; + return 0; +} + +/* + * str2clrsetmasks() - parse bitmask argument and set the clear and + * the set bitmap mask. A concatenation (done with ',') of these terms + * is recognized: + * +<bitnr>[-<bitnr>] or -<bitnr>[-<bitnr>] + * <bitnr> may be any valid number (hex, decimal or octal) in the range + * 0...bits-1; the leading + or - is required. Here are some examples: + * +0-15,+32,-128,-0xFF + * -0-255,+1-16,+0x128 + * +1,+2,+3,+4,-5,-7-10 + * Returns a clear and a set bitmask. Every positive value in the string + * results in a bit set in the set mask and every negative value in the + * string results in a bit SET in the clear mask. As a bit may be touched + * more than once, the last 'operation' wins: +0-255,-128 = all but bit + * 128 set in the set mask, only bit 128 set in the clear mask. + */ +static int str2clrsetmasks(const char *str, + unsigned long *clrmap, + unsigned long *setmap, + int bits) +{ + int a, i, z; + char *np, sign; + + /* bits needs to be a multiple of 8 */ + if (bits & 0x07) + return -EINVAL; + + memset(clrmap, 0, bits / 8); + memset(setmap, 0, bits / 8); + + while (*str) { + sign = *str++; + if (sign != '+' && sign != '-') + return -EINVAL; + a = z = simple_strtoul(str, &np, 0); + if (str == np || a >= bits) + return -EINVAL; + str = np; + if (*str == '-') { + z = simple_strtoul(++str, &np, 0); + if (str == np || a > z || z >= bits) + return -EINVAL; + str = np; + } + for (i = a; i <= z; i++) + if (sign == '+') { + set_bit_inv(i, setmap); + clear_bit_inv(i, clrmap); + } else { + clear_bit_inv(i, setmap); + set_bit_inv(i, clrmap); + } + while (*str == ',' || *str == '\n') + str++; + } + + return 0; +} + +/* + * process_mask_arg() - parse a bitmap string and clear/set the + * bits in the bitmap accordingly. The string may be given as + * absolute value, a hex string like 0x1F2E3D4C5B6A" simple over- + * writing the current content of the bitmap. Or as relative string + * like "+1-16,-32,-0x40,+128" where only single bits or ranges of + * bits are cleared or set. Distinction is done based on the very + * first character which may be '+' or '-' for the relative string + * and othewise assume to be an absolute value string. If parsing fails + * a negative errno value is returned. All arguments and bitmaps are + * big endian order. + */ +static int process_mask_arg(const char *str, + unsigned long *bitmap, int bits, + struct mutex *lock) +{ + int i; + + /* bits needs to be a multiple of 8 */ + if (bits & 0x07) + return -EINVAL; + + if (*str == '+' || *str == '-') { + DECLARE_BITMAP(clrm, bits); + DECLARE_BITMAP(setm, bits); + + i = str2clrsetmasks(str, clrm, setm, bits); + if (i) + return i; + if (mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + for (i = 0; i < bits; i++) { + if (test_bit_inv(i, clrm)) + clear_bit_inv(i, bitmap); + if (test_bit_inv(i, setm)) + set_bit_inv(i, bitmap); + } + } else { + DECLARE_BITMAP(setm, bits); + + i = hex2bitmap(str, setm, bits); + if (i) + return i; + if (mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + for (i = 0; i < bits; i++) + if (test_bit_inv(i, setm)) + set_bit_inv(i, bitmap); + else + clear_bit_inv(i, bitmap); + } + mutex_unlock(lock); + + return 0; +} + +/* * AP bus attributes. */ + static ssize_t ap_domain_show(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); @@ -764,7 +1025,8 @@ static ssize_t ap_domain_store(struct bus_type *bus, int domain; if (sscanf(buf, "%i\n", &domain) != 1 || - domain < 0 || domain > ap_max_domain_id) + domain < 0 || domain > ap_max_domain_id || + !test_bit_inv(domain, ap_perms.aqm)) return -EINVAL; spin_lock_bh(&ap_domain_lock); ap_domain_index = domain; @@ -775,7 +1037,7 @@ static ssize_t ap_domain_store(struct bus_type *bus, return count; } -static BUS_ATTR(ap_domain, 0644, ap_domain_show, ap_domain_store); +static BUS_ATTR_RW(ap_domain); static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) { @@ -790,8 +1052,7 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) ap_configuration->adm[6], ap_configuration->adm[7]); } -static BUS_ATTR(ap_control_domain_mask, 0444, - ap_control_domain_mask_show, NULL); +static BUS_ATTR_RO(ap_control_domain_mask); static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) { @@ -806,13 +1067,7 @@ static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) ap_configuration->aqm[6], ap_configuration->aqm[7]); } -static BUS_ATTR(ap_usage_domain_mask, 0444, - ap_usage_domain_mask_show, NULL); - -static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); -} +static BUS_ATTR_RO(ap_usage_domain_mask); static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) { @@ -820,10 +1075,15 @@ static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) ap_using_interrupts() ? 1 : 0); } -static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL); +static BUS_ATTR_RO(ap_interrupts); + +static ssize_t config_time_show(struct bus_type *bus, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); +} -static ssize_t ap_config_time_store(struct bus_type *bus, - const char *buf, size_t count) +static ssize_t config_time_store(struct bus_type *bus, + const char *buf, size_t count) { int time; @@ -834,15 +1094,15 @@ static ssize_t ap_config_time_store(struct bus_type *bus, return count; } -static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store); +static BUS_ATTR_RW(config_time); -static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf) +static ssize_t poll_thread_show(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0); } -static ssize_t ap_poll_thread_store(struct bus_type *bus, - const char *buf, size_t count) +static ssize_t poll_thread_store(struct bus_type *bus, + const char *buf, size_t count) { int flag, rc; @@ -857,7 +1117,7 @@ static ssize_t ap_poll_thread_store(struct bus_type *bus, return count; } -static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store); +static BUS_ATTR_RW(poll_thread); static ssize_t poll_timeout_show(struct bus_type *bus, char *buf) { @@ -886,7 +1146,7 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, return count; } -static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); +static BUS_ATTR_RW(poll_timeout); static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) { @@ -899,7 +1159,69 @@ static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id); } -static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL); +static BUS_ATTR_RO(ap_max_domain_id); + +static ssize_t apmask_show(struct bus_type *bus, char *buf) +{ + int rc; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + rc = snprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_perms.apm[0], ap_perms.apm[1], + ap_perms.apm[2], ap_perms.apm[3]); + mutex_unlock(&ap_perms_mutex); + + return rc; +} + +static ssize_t apmask_store(struct bus_type *bus, const char *buf, + size_t count) +{ + int rc; + + rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex); + if (rc) + return rc; + + ap_bus_revise_bindings(); + + return count; +} + +static BUS_ATTR_RW(apmask); + +static ssize_t aqmask_show(struct bus_type *bus, char *buf) +{ + int rc; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + rc = snprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_perms.aqm[0], ap_perms.aqm[1], + ap_perms.aqm[2], ap_perms.aqm[3]); + mutex_unlock(&ap_perms_mutex); + + return rc; +} + +static ssize_t aqmask_store(struct bus_type *bus, const char *buf, + size_t count) +{ + int rc; + + rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex); + if (rc) + return rc; + + ap_bus_revise_bindings(); + + return count; +} + +static BUS_ATTR_RW(aqmask); static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, @@ -910,6 +1232,8 @@ static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_interrupts, &bus_attr_poll_timeout, &bus_attr_ap_max_domain_id, + &bus_attr_apmask, + &bus_attr_aqmask, NULL, }; @@ -938,7 +1262,8 @@ static int ap_select_domain(void) best_domain = -1; max_count = 0; for (i = 0; i < AP_DOMAINS; i++) { - if (!ap_test_config_domain(i)) + if (!ap_test_config_domain(i) || + !test_bit_inv(i, ap_perms.aqm)) continue; count = 0; for (j = 0; j < AP_DEVICES; j++) { @@ -956,7 +1281,7 @@ static int ap_select_domain(void) best_domain = i; } } - if (best_domain >= 0){ + if (best_domain >= 0) { ap_domain_index = best_domain; AP_DBF(DBF_DEBUG, "new ap_domain_index=%d\n", ap_domain_index); spin_unlock_bh(&ap_domain_lock); @@ -1038,7 +1363,7 @@ static void ap_scan_bus(struct work_struct *unused) unsigned int func = 0; int rc, id, dom, borked, domains, defdomdevs = 0; - AP_DBF(DBF_DEBUG, "ap_scan_bus running\n"); + AP_DBF(DBF_DEBUG, "%s running\n", __func__); ap_query_configuration(ap_configuration); if (ap_select_domain() != 0) @@ -1163,7 +1488,8 @@ static void ap_scan_bus(struct work_struct *unused) } /* end device loop */ if (defdomdevs < 1) - AP_DBF(DBF_INFO, "no queue device with default domain %d available\n", + AP_DBF(DBF_INFO, + "no queue device with default domain %d available\n", ap_domain_index); out: @@ -1187,6 +1513,27 @@ static int __init ap_debug_init(void) return 0; } +static void __init ap_perms_init(void) +{ + /* all resources useable if no kernel parameter string given */ + memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm)); + memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm)); + + /* apm kernel parameter string */ + if (apm_str) { + memset(&ap_perms.apm, 0, sizeof(ap_perms.apm)); + process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES, + &ap_perms_mutex); + } + + /* aqm kernel parameter string */ + if (aqm_str) { + memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm)); + process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS, + &ap_perms_mutex); + } +} + /** * ap_module_init(): The module initialization code. * @@ -1201,11 +1548,14 @@ static int __init ap_module_init(void) if (rc) return rc; - if (ap_instructions_available() != 0) { + if (!ap_instructions_available()) { pr_warn("The hardware system does not support AP instructions\n"); return -ENODEV; } + /* set up the AP permissions (ap and aq masks) */ + ap_perms_init(); + /* Get AP configuration data if available */ ap_init_configuration(); @@ -1214,7 +1564,9 @@ static int __init ap_module_init(void) ap_max_domain_id ? ap_max_domain_id : AP_DOMAINS - 1; else max_domain_id = 15; - if (ap_domain_index < -1 || ap_domain_index > max_domain_id) { + if (ap_domain_index < -1 || ap_domain_index > max_domain_id || + (ap_domain_index >= 0 && + !test_bit_inv(ap_domain_index, ap_perms.aqm))) { pr_warn("%d is not a valid cryptographic domain\n", ap_domain_index); ap_domain_index = -1; diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 936541937e15..5246cd8c16a6 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright IBM Corp. 2006, 2012 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> @@ -117,9 +117,18 @@ enum ap_wait { struct ap_device; struct ap_message; +/* + * The ap driver struct includes a flags field which holds some info for + * the ap bus about the driver. Currently only one flag is supported and + * used: The DEFAULT flag marks an ap driver as a default driver which is + * used together with the apmask and aqmask whitelisting of the ap bus. + */ +#define AP_DRIVER_FLAG_DEFAULT 0x0001 + struct ap_driver { struct device_driver driver; struct ap_device_id *ids; + unsigned int flags; int (*probe)(struct ap_device *); void (*remove)(struct ap_device *); @@ -167,7 +176,7 @@ struct ap_queue { int pendingq_count; /* # requests on pendingq list. */ int requestq_count; /* # requests on requestq list. */ int total_request_count; /* # requests ever for this AP device.*/ - int request_timeout; /* Request timout in jiffies. */ + int request_timeout; /* Request timeout in jiffies. */ struct timer_list timeout; /* Timer for request timeouts. */ struct list_head pendingq; /* List of message sent to AP queue. */ struct list_head requestq; /* List of message yet to be sent. */ @@ -248,4 +257,27 @@ void ap_queue_resume(struct ap_device *ap_dev); struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type, int comp_device_type, unsigned int functions); +/* + * check APQN for owned/reserved by ap bus and default driver(s). + * Checks if this APQN is or will be in use by the ap bus + * and the default set of drivers. + * If yes, returns 1, if not returns 0. On error a negative + * errno value is returned. + */ +int ap_owned_by_def_drv(int card, int queue); + +/* + * check 'matrix' of APQNs for owned/reserved by ap bus and + * default driver(s). + * Checks if there is at least one APQN in the given 'matrix' + * marked as owned/reserved by the ap bus and default driver(s). + * If such an APQN is found the return value is 1, otherwise + * 0 is returned. On error a negative errno value is returned. + * The parameter apm is a bitmask which should be declared + * as DECLARE_BITMAP(apm, AP_DEVICES), the aqm parameter is + * similar, should be declared as DECLARE_BITMAP(aqm, AP_DOMAINS). + */ +int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, + unsigned long *aqm); + #endif /* _AP_BUS_H_ */ diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index c13e43292cb7..63b4cc6cd7e5 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -18,35 +18,35 @@ /* * AP card related attributes. */ -static ssize_t ap_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); } -static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); +static DEVICE_ATTR_RO(hwtype); -static ssize_t ap_raw_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t raw_hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); } -static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL); +static DEVICE_ATTR_RO(raw_hwtype); -static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t depth_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct ap_card *ac = to_ap_card(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); } -static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); +static DEVICE_ATTR_RO(depth); static ssize_t ap_functions_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -58,9 +58,9 @@ static ssize_t ap_functions_show(struct device *dev, static DEVICE_ATTR_RO(ap_functions); -static ssize_t ap_req_count_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ap_card *ac = to_ap_card(dev); unsigned int req_cnt; @@ -72,9 +72,9 @@ static ssize_t ap_req_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); } -static ssize_t ap_req_count_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t request_count_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct ap_card *ac = to_ap_card(dev); struct ap_queue *aq; @@ -88,10 +88,10 @@ static ssize_t ap_req_count_store(struct device *dev, return count; } -static DEVICE_ATTR(request_count, 0644, ap_req_count_show, ap_req_count_store); +static DEVICE_ATTR_RW(request_count); -static ssize_t ap_requestq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); struct ap_queue *aq; @@ -105,10 +105,10 @@ static ssize_t ap_requestq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); } -static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); +static DEVICE_ATTR_RO(requestq_count); -static ssize_t ap_pendingq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); struct ap_queue *aq; @@ -122,15 +122,15 @@ static ssize_t ap_pendingq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); } -static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); +static DEVICE_ATTR_RO(pendingq_count); -static ssize_t ap_modalias_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); } -static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); +static DEVICE_ATTR_RO(modalias); static struct attribute *ap_card_dev_attrs[] = { &dev_attr_hwtype.attr, diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index e365171fe28f..66f7334bcb03 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -462,9 +462,9 @@ EXPORT_SYMBOL(ap_queue_resume); /* * AP queue related attributes. */ -static ssize_t ap_req_count_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ap_queue *aq = to_ap_queue(dev); unsigned int req_cnt; @@ -475,9 +475,9 @@ static ssize_t ap_req_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); } -static ssize_t ap_req_count_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t request_count_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct ap_queue *aq = to_ap_queue(dev); @@ -488,10 +488,10 @@ static ssize_t ap_req_count_store(struct device *dev, return count; } -static DEVICE_ATTR(request_count, 0644, ap_req_count_show, ap_req_count_store); +static DEVICE_ATTR_RW(request_count); -static ssize_t ap_requestq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); unsigned int reqq_cnt = 0; @@ -502,10 +502,10 @@ static ssize_t ap_requestq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); } -static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); +static DEVICE_ATTR_RO(requestq_count); -static ssize_t ap_pendingq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); unsigned int penq_cnt = 0; @@ -516,10 +516,10 @@ static ssize_t ap_pendingq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); } -static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); +static DEVICE_ATTR_RO(pendingq_count); -static ssize_t ap_reset_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t reset_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); int rc = 0; @@ -541,10 +541,10 @@ static ssize_t ap_reset_show(struct device *dev, return rc; } -static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL); +static DEVICE_ATTR_RO(reset); -static ssize_t ap_interrupt_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t interrupt_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); int rc = 0; @@ -560,7 +560,7 @@ static ssize_t ap_interrupt_show(struct device *dev, return rc; } -static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL); +static DEVICE_ATTR_RO(interrupt); static struct attribute *ap_queue_dev_attrs[] = { &dev_attr_request_count.attr, diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index e663432395c1..1b4001e0285f 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -82,20 +82,20 @@ static int check_secaeskeytoken(const u8 *token, int keybitsize) if (t->type != 0x01) { DEBUG_ERR( - "check_secaeskeytoken secure token check failed, type mismatch 0x%02x != 0x01\n", - (int) t->type); + "%s secure token check failed, type mismatch 0x%02x != 0x01\n", + __func__, (int) t->type); return -EINVAL; } if (t->version != 0x04) { DEBUG_ERR( - "check_secaeskeytoken secure token check failed, version mismatch 0x%02x != 0x04\n", - (int) t->version); + "%s secure token check failed, version mismatch 0x%02x != 0x04\n", + __func__, (int) t->version); return -EINVAL; } if (keybitsize > 0 && t->bitsize != keybitsize) { DEBUG_ERR( - "check_secaeskeytoken secure token check failed, bitsize mismatch %d != %d\n", - (int) t->bitsize, keybitsize); + "%s secure token check failed, bitsize mismatch %d != %d\n", + __func__, (int) t->bitsize, keybitsize); return -EINVAL; } @@ -270,8 +270,8 @@ int pkey_genseckey(u16 cardnr, u16 domain, break; default: DEBUG_ERR( - "pkey_genseckey unknown/unsupported keytype %d\n", - keytype); + "%s unknown/unsupported keytype %d\n", + __func__, keytype); rc = -EINVAL; goto out; } @@ -290,15 +290,16 @@ int pkey_genseckey(u16 cardnr, u16 domain, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "pkey_genseckey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "pkey_genseckey secure key generate failure, card response %d/%d\n", + "%s secure key generate failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -315,8 +316,8 @@ int pkey_genseckey(u16 cardnr, u16 domain, - sizeof(prepparm->lv3.keyblock.tokattr); if (seckeysize != SECKEYBLOBSIZE) { DEBUG_ERR( - "pkey_genseckey secure token size mismatch %d != %d bytes\n", - seckeysize, SECKEYBLOBSIZE); + "%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); rc = -EIO; goto out; } @@ -407,8 +408,8 @@ int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, break; default: DEBUG_ERR( - "pkey_clr2seckey unknown/unsupported keytype %d\n", - keytype); + "%s unknown/unsupported keytype %d\n", + __func__, keytype); rc = -EINVAL; goto out; } @@ -427,15 +428,16 @@ int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "pkey_clr2seckey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "pkey_clr2seckey clear key import failure, card response %d/%d\n", + "%s clear key import failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -452,8 +454,8 @@ int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, - sizeof(prepparm->lv3.keyblock.tokattr); if (seckeysize != SECKEYBLOBSIZE) { DEBUG_ERR( - "pkey_clr2seckey secure token size mismatch %d != %d bytes\n", - seckeysize, SECKEYBLOBSIZE); + "%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); rc = -EIO; goto out; } @@ -553,15 +555,16 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "pkey_sec2protkey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "pkey_sec2protkey unwrap secure key failure, card response %d/%d\n", + "%s unwrap secure key failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -569,7 +572,8 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, } if (prepcblk->ccp_rscode != 0) { DEBUG_WARN( - "pkey_sec2protkey unwrap secure key warning, card response %d/%d\n", + "%s unwrap secure key warning, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); } @@ -581,8 +585,8 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, /* check the returned keyblock */ if (prepparm->lv3.keyblock.version != 0x01) { DEBUG_ERR( - "pkey_sec2protkey reply param keyblock version mismatch 0x%02x != 0x01\n", - (int) prepparm->lv3.keyblock.version); + "%s reply param keyblock version mismatch 0x%02x != 0x01\n", + __func__, (int) prepparm->lv3.keyblock.version); rc = -EIO; goto out; } @@ -599,8 +603,8 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, protkey->type = PKEY_KEYTYPE_AES_256; break; default: - DEBUG_ERR("pkey_sec2protkey unknown/unsupported keytype %d\n", - prepparm->lv3.keyblock.keylen); + DEBUG_ERR("%s unknown/unsupported keytype %d\n", + __func__, prepparm->lv3.keyblock.keylen); rc = -EIO; goto out; } @@ -638,8 +642,8 @@ int pkey_clr2protkey(u32 keytype, fc = CPACF_PCKMO_ENC_AES_256_KEY; break; default: - DEBUG_ERR("pkey_clr2protkey unknown/unsupported keytype %d\n", - keytype); + DEBUG_ERR("%s unknown/unsupported keytype %d\n", + __func__, keytype); return -EINVAL; } @@ -713,15 +717,16 @@ static int query_crypto_facility(u16 cardnr, u16 domain, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "query_crypto_facility zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "query_crypto_facility unwrap secure key failure, card response %d/%d\n", + "%s unwrap secure key failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -993,7 +998,7 @@ int pkey_skey2pkey(const struct pkey_seckey *seckey, } if (rc) - DEBUG_DBG("pkey_skey2pkey failed rc=%d\n", rc); + DEBUG_DBG("%s failed rc=%d\n", __func__, rc); return rc; } @@ -1030,7 +1035,7 @@ int pkey_verifykey(const struct pkey_seckey *seckey, if (rc) goto out; if (t->mkvp == mkvp[1]) { - DEBUG_DBG("pkey_verifykey secure key has old mkvp\n"); + DEBUG_DBG("%s secure key has old mkvp\n", __func__); if (pattributes) *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP; } @@ -1041,7 +1046,7 @@ int pkey_verifykey(const struct pkey_seckey *seckey, *pdomain = domain; out: - DEBUG_DBG("pkey_verifykey rc=%d\n", rc); + DEBUG_DBG("%s rc=%d\n", __func__, rc); return rc; } EXPORT_SYMBOL(pkey_verifykey); @@ -1064,7 +1069,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_genseckey(kgs.cardnr, kgs.domain, kgs.keytype, &kgs.seckey); - DEBUG_DBG("pkey_ioctl pkey_genseckey()=%d\n", rc); + DEBUG_DBG("%s pkey_genseckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ugs, &kgs, sizeof(kgs))) @@ -1079,7 +1084,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype, &kcs.clrkey, &kcs.seckey); - DEBUG_DBG("pkey_ioctl pkey_clr2seckey()=%d\n", rc); + DEBUG_DBG("%s pkey_clr2seckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ucs, &kcs, sizeof(kcs))) @@ -1095,7 +1100,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_sec2protkey(ksp.cardnr, ksp.domain, &ksp.seckey, &ksp.protkey); - DEBUG_DBG("pkey_ioctl pkey_sec2protkey()=%d\n", rc); + DEBUG_DBG("%s pkey_sec2protkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(usp, &ksp, sizeof(ksp))) @@ -1110,7 +1115,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_clr2protkey(kcp.keytype, &kcp.clrkey, &kcp.protkey); - DEBUG_DBG("pkey_ioctl pkey_clr2protkey()=%d\n", rc); + DEBUG_DBG("%s pkey_clr2protkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ucp, &kcp, sizeof(kcp))) @@ -1126,7 +1131,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_findcard(&kfc.seckey, &kfc.cardnr, &kfc.domain, 1); - DEBUG_DBG("pkey_ioctl pkey_findcard()=%d\n", rc); + DEBUG_DBG("%s pkey_findcard()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ufc, &kfc, sizeof(kfc))) @@ -1140,7 +1145,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; rc = pkey_skey2pkey(&ksp.seckey, &ksp.protkey); - DEBUG_DBG("pkey_ioctl pkey_skey2pkey()=%d\n", rc); + DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(usp, &ksp, sizeof(ksp))) @@ -1155,7 +1160,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain, &kvk.keysize, &kvk.attributes); - DEBUG_DBG("pkey_ioctl pkey_verifykey()=%d\n", rc); + DEBUG_DBG("%s pkey_verifykey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(uvk, &kvk, sizeof(kvk))) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index febcdb5135bf..e6854127b434 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -50,7 +50,7 @@ EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_req); EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_rep); static int zcrypt_hwrng_seed = 1; -module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP); +module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, 0440); MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on)."); DEFINE_SPINLOCK(zcrypt_list_lock); @@ -182,7 +182,8 @@ static inline void zcrypt_drop_queue(struct zcrypt_card *zc, static inline bool zcrypt_card_compare(struct zcrypt_card *zc, struct zcrypt_card *pref_zc, - unsigned weight, unsigned pref_weight) + unsigned int weight, + unsigned int pref_weight) { if (!pref_zc) return false; @@ -196,7 +197,8 @@ static inline bool zcrypt_card_compare(struct zcrypt_card *zc, static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, struct zcrypt_queue *pref_zq, - unsigned weight, unsigned pref_weight) + unsigned int weight, + unsigned int pref_weight) { if (!pref_zq) return false; @@ -792,6 +794,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ICARSAMODEXPO: { struct ica_rsa_modexpo __user *umex = (void __user *) arg; struct ica_rsa_modexpo mex; + if (copy_from_user(&mex, umex, sizeof(mex))) return -EFAULT; do { @@ -811,6 +814,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ICARSACRT: { struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg; struct ica_rsa_modexpo_crt crt; + if (copy_from_user(&crt, ucrt, sizeof(crt))) return -EFAULT; do { @@ -830,6 +834,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ZSECSENDCPRB: { struct ica_xcRB __user *uxcRB = (void __user *) arg; struct ica_xcRB xcRB; + if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) return -EFAULT; do { @@ -849,6 +854,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ZSENDEP11CPRB: { struct ep11_urb __user *uxcrb = (void __user *)arg; struct ep11_urb xcrb; + if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) return -EFAULT; do { @@ -1037,7 +1043,7 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, return -EFAULT; crt64.inputdata = compat_ptr(crt32.inputdata); crt64.inputdatalength = crt32.inputdatalength; - crt64.outputdata= compat_ptr(crt32.outputdata); + crt64.outputdata = compat_ptr(crt32.outputdata); crt64.outputdatalength = crt32.outputdatalength; crt64.bp_key = compat_ptr(crt32.bp_key); crt64.bq_key = compat_ptr(crt32.bq_key); @@ -1063,20 +1069,20 @@ struct compat_ica_xcRB { unsigned int user_defined; unsigned short request_ID; unsigned int request_control_blk_length; - unsigned char padding1[16 - sizeof (compat_uptr_t)]; + unsigned char padding1[16 - sizeof(compat_uptr_t)]; compat_uptr_t request_control_blk_addr; unsigned int request_data_length; - char padding2[16 - sizeof (compat_uptr_t)]; + char padding2[16 - sizeof(compat_uptr_t)]; compat_uptr_t request_data_address; unsigned int reply_control_blk_length; - char padding3[16 - sizeof (compat_uptr_t)]; + char padding3[16 - sizeof(compat_uptr_t)]; compat_uptr_t reply_control_blk_addr; unsigned int reply_data_length; - char padding4[16 - sizeof (compat_uptr_t)]; + char padding4[16 - sizeof(compat_uptr_t)]; compat_uptr_t reply_data_addr; unsigned short priority_window; unsigned int status; -} __attribute__((packed)); +} __packed; static long trans_xcRB32(struct file *filp, unsigned int cmd, unsigned long arg) @@ -1120,7 +1126,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, xcRB32.reply_data_length = xcRB64.reply_data_length; xcRB32.status = xcRB64.status; if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32))) - return -EFAULT; + return -EFAULT; return rc; } @@ -1182,10 +1188,10 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) rc = zcrypt_rng((char *) zcrypt_rng_buffer); if (rc < 0) return -EIO; - zcrypt_rng_buffer_index = rc / sizeof *data; + zcrypt_rng_buffer_index = rc / sizeof(*data); } *data = zcrypt_rng_buffer[--zcrypt_rng_buffer_index]; - return sizeof *data; + return sizeof(*data); } static struct hwrng zcrypt_rng_dev = { diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index f149a8fee60d..a848625c1a5a 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index da2c8dfd4d74..40cd4c1c2de8 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -38,28 +38,28 @@ * Device attributes common for all crypto card devices. */ -static ssize_t zcrypt_card_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t type_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct zcrypt_card *zc = to_ap_card(dev)->private; return snprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); } -static DEVICE_ATTR(type, 0444, zcrypt_card_type_show, NULL); +static DEVICE_ATTR_RO(type); -static ssize_t zcrypt_card_online_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t online_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_card *zc = to_ap_card(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", zc->online); } -static ssize_t zcrypt_card_online_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct zcrypt_card *zc = to_ap_card(dev)->private; struct zcrypt_queue *zq; @@ -80,19 +80,18 @@ static ssize_t zcrypt_card_online_store(struct device *dev, return count; } -static DEVICE_ATTR(online, 0644, zcrypt_card_online_show, - zcrypt_card_online_store); +static DEVICE_ATTR_RW(online); -static ssize_t zcrypt_card_load_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t load_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_card *zc = to_ap_card(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zc->load)); } -static DEVICE_ATTR(load, 0444, zcrypt_card_load_show, NULL); +static DEVICE_ATTR_RO(load); static struct attribute *zcrypt_card_attrs[] = { &dev_attr_type.attr, diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h index 1752622b95f7..e5b5c02c9d67 100644 --- a/drivers/s390/crypto/zcrypt_cca_key.h +++ b/drivers/s390/crypto/zcrypt_cca_key.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * @@ -31,7 +31,7 @@ struct cca_token_hdr { unsigned char version; unsigned short token_length; unsigned char reserved[4]; -} __attribute__((packed)); +} __packed; #define CCA_TKN_HDR_ID_EXT 0x1E @@ -51,7 +51,7 @@ struct cca_public_sec { unsigned short exponent_len; unsigned short modulus_bit_len; unsigned short modulus_byte_len; /* In a private key, this is 0 */ -} __attribute__((packed)); +} __packed; /** * mapping for the cca private CRT key 'token' @@ -85,7 +85,7 @@ struct cca_pvt_ext_CRT_sec { unsigned short pad_len; unsigned char reserved4[52]; unsigned char confounder[8]; -} __attribute__((packed)); +} __packed; #define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08 #define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40 @@ -114,7 +114,7 @@ static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex, void *p) struct cca_token_hdr pubHdr; struct cca_public_sec pubSec; char exponent[0]; - } __attribute__((packed)) *key = p; + } __packed *key = p; unsigned char *temp; int i; @@ -183,7 +183,7 @@ static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt, void *p) struct cca_token_hdr token; struct cca_pvt_ext_CRT_sec pvt; char key_parts[0]; - } __attribute__((packed)) *key = p; + } __packed *key = p; struct cca_public_sec *pub; int short_len, long_len, pad_len, key_len, size; diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index e701194d3611..f4ae5fa30ec9 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -145,6 +145,7 @@ static struct ap_driver zcrypt_cex2a_card_driver = { .probe = zcrypt_cex2a_card_probe, .remove = zcrypt_cex2a_card_remove, .ids = zcrypt_cex2a_card_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; /** @@ -208,6 +209,7 @@ static struct ap_driver zcrypt_cex2a_queue_driver = { .suspend = ap_queue_suspend, .resume = ap_queue_resume, .ids = zcrypt_cex2a_queue_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; int __init zcrypt_cex2a_init(void) diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h index c3c116777c93..66d58bc87c66 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.h +++ b/drivers/s390/crypto/zcrypt_cex2a.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * @@ -30,7 +30,7 @@ struct type50_hdr { unsigned char reserved2; unsigned char ignored; unsigned short reserved3; -} __attribute__((packed)); +} __packed; #define TYPE50_TYPE_CODE 0x50 @@ -49,7 +49,7 @@ struct type50_meb1_msg { unsigned char exponent[128]; unsigned char modulus[128]; unsigned char message[128]; -} __attribute__((packed)); +} __packed; /* Mod-Exp, with a large modulus */ struct type50_meb2_msg { @@ -59,7 +59,7 @@ struct type50_meb2_msg { unsigned char exponent[256]; unsigned char modulus[256]; unsigned char message[256]; -} __attribute__((packed)); +} __packed; /* Mod-Exp, with a larger modulus */ struct type50_meb3_msg { @@ -69,7 +69,7 @@ struct type50_meb3_msg { unsigned char exponent[512]; unsigned char modulus[512]; unsigned char message[512]; -} __attribute__((packed)); +} __packed; /* CRT, with a small modulus */ struct type50_crb1_msg { @@ -82,7 +82,7 @@ struct type50_crb1_msg { unsigned char dq[64]; unsigned char u[64]; unsigned char message[128]; -} __attribute__((packed)); +} __packed; /* CRT, with a large modulus */ struct type50_crb2_msg { @@ -95,7 +95,7 @@ struct type50_crb2_msg { unsigned char dq[128]; unsigned char u[128]; unsigned char message[256]; -} __attribute__((packed)); +} __packed; /* CRT, with a larger modulus */ struct type50_crb3_msg { @@ -108,7 +108,7 @@ struct type50_crb3_msg { unsigned char dq[256]; unsigned char u[256]; unsigned char message[512]; -} __attribute__((packed)); +} __packed; /** * The type 80 response family is associated with a CEX2A card. @@ -128,7 +128,7 @@ struct type80_hdr { unsigned char code; /* 0x00 */ unsigned char reserved2[3]; unsigned char reserved3[8]; -} __attribute__((packed)); +} __packed; int zcrypt_cex2a_init(void); void zcrypt_cex2a_exit(void); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index f305538334ad..35d58dbbc4da 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -214,6 +214,7 @@ static struct ap_driver zcrypt_cex4_card_driver = { .probe = zcrypt_cex4_card_probe, .remove = zcrypt_cex4_card_remove, .ids = zcrypt_cex4_card_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; /** @@ -283,6 +284,7 @@ static struct ap_driver zcrypt_cex4_queue_driver = { .suspend = ap_queue_suspend, .resume = ap_queue_resume, .ids = zcrypt_cex4_queue_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; int __init zcrypt_cex4_init(void) diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 01598d83c60a..6f7ebc1dbe10 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index afe1b2bcd7ec..f159662c907b 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -27,13 +27,14 @@ #include "zcrypt_error.h" #include "zcrypt_msgtype50.h" -#define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ +/* 4096 bits */ +#define CEX3A_MAX_MOD_SIZE 512 -#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ +/* max outputdatalength + type80_hdr */ +#define CEX2A_MAX_RESPONSE_SIZE 0x110 -#define CEX3A_MAX_RESPONSE_SIZE 0x210 /* 512 bit modulus - * (max outputdatalength) + - * type80_hdr*/ +/* 512 bit modulus, (max outputdatalength) + type80_hdr */ +#define CEX3A_MAX_RESPONSE_SIZE 0x210 MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \ @@ -209,6 +210,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, if (mod_len <= 128) { struct type50_meb1_msg *meb1 = ap_msg->message; + memset(meb1, 0, sizeof(*meb1)); ap_msg->length = sizeof(*meb1); meb1->header.msg_type_code = TYPE50_TYPE_CODE; @@ -219,6 +221,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, inp = meb1->message + sizeof(meb1->message) - mod_len; } else if (mod_len <= 256) { struct type50_meb2_msg *meb2 = ap_msg->message; + memset(meb2, 0, sizeof(*meb2)); ap_msg->length = sizeof(*meb2); meb2->header.msg_type_code = TYPE50_TYPE_CODE; @@ -229,6 +232,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, inp = meb2->message + sizeof(meb2->message) - mod_len; } else if (mod_len <= 512) { struct type50_meb3_msg *meb3 = ap_msg->message; + memset(meb3, 0, sizeof(*meb3)); ap_msg->length = sizeof(*meb3); meb3->header.msg_type_code = TYPE50_TYPE_CODE; @@ -274,6 +278,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, */ if (mod_len <= 128) { /* up to 1024 bit key size */ struct type50_crb1_msg *crb1 = ap_msg->message; + memset(crb1, 0, sizeof(*crb1)); ap_msg->length = sizeof(*crb1); crb1->header.msg_type_code = TYPE50_TYPE_CODE; @@ -287,6 +292,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, inp = crb1->message + sizeof(crb1->message) - mod_len; } else if (mod_len <= 256) { /* up to 2048 bit key size */ struct type50_crb2_msg *crb2 = ap_msg->message; + memset(crb2, 0, sizeof(*crb2)); ap_msg->length = sizeof(*crb2); crb2->header.msg_type_code = TYPE50_TYPE_CODE; @@ -301,6 +307,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, } else if ((mod_len <= 512) && /* up to 4096 bit key size */ (zq->zcard->max_mod_size == CEX3A_MAX_MOD_SIZE)) { struct type50_crb3_msg *crb3 = ap_msg->message; + memset(crb3, 0, sizeof(*crb3)); ap_msg->length = sizeof(*crb3); crb3->header.msg_type_code = TYPE50_TYPE_CODE; diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h index 0a36545cfb8e..8530f652ea4f 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.h +++ b/drivers/s390/crypto/zcrypt_msgtype50.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * @@ -17,10 +17,10 @@ #define MSGTYPE50_NAME "zcrypt_msgtype50" #define MSGTYPE50_VARIANT_DEFAULT 0 -#define MSGTYPE50_CRB2_MAX_MSG_SIZE 0x390 /*sizeof(struct type50_crb2_msg)*/ -#define MSGTYPE50_CRB3_MAX_MSG_SIZE 0x710 /*sizeof(struct type50_crb3_msg)*/ +#define MSGTYPE50_CRB2_MAX_MSG_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */ +#define MSGTYPE50_CRB3_MAX_MSG_SIZE 0x710 /* sizeof(struct type50_crb3_msg) */ -#define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/ +#define MSGTYPE_ADJUSTMENT 0x08 /* type04 extension (not needed in type50) */ unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *, int *); unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *, int *); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index e70ae078c86b..2101776a8148 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -421,8 +421,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE) return -EINVAL; - /* Overflow check - sum must be greater (or equal) than the largest operand */ + /* + * Overflow check + * sum must be greater (or equal) than the largest operand + */ req_sumlen = CEIL4(xcRB->request_control_blk_length) + xcRB->request_data_length; if ((CEIL4(xcRB->request_control_blk_length) <= @@ -442,8 +444,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, if (replylen > MSGTYPE06_MAX_MSG_SIZE) return -EINVAL; - /* Overflow check - sum must be greater (or equal) than the largest operand */ + /* + * Overflow check + * sum must be greater (or equal) than the largest operand + */ resp_sumlen = CEIL4(xcRB->reply_control_blk_length) + xcRB->reply_data_length; if ((CEIL4(xcRB->reply_control_blk_length) <= xcRB->reply_data_length) ? @@ -454,7 +458,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, /* prepare type6 header */ msg->hdr = static_type6_hdrX; - memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); + memcpy(msg->hdr.agent_id, &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); msg->hdr.ToCardLen1 = xcRB->request_control_blk_length; if (xcRB->request_data_length) { msg->hdr.offset2 = msg->hdr.offset1 + rcblen; @@ -806,8 +810,10 @@ static int convert_response_ica(struct zcrypt_queue *zq, if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_ica(zq, reply, outputdata, outputdatalength); - /* Fall through, no break, incorrect cprb version is an unknown - * response */ + /* + * Fall through, no break, incorrect cprb version is an unknown + * response + */ default: /* Unknown response type, this should NEVER EVER happen */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", @@ -840,8 +846,10 @@ static int convert_response_xcrb(struct zcrypt_queue *zq, } if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_xcrb(zq, reply, xcRB); - /* Fall through, no break, incorrect cprb version is an unknown - * response */ + /* + * Fall through, no break, incorrect cprb version is an unknown + * response + */ default: /* Unknown response type, this should NEVER EVER happen */ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ zq->online = 0; @@ -901,8 +909,10 @@ static int convert_response_rng(struct zcrypt_queue *zq, return -EINVAL; if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_rng(zq, reply, data); - /* Fall through, no break, incorrect cprb version is an unknown - * response */ + /* + * Fall through, no break, incorrect cprb version is an unknown + * response + */ default: /* Unknown response type, this should NEVER EVER happen */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", @@ -1004,7 +1014,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, } } else { memcpy(msg->message, reply->message, sizeof(error_reply)); - } + } out: complete(&(resp_type->work)); } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index d314f4525518..e4c2f37d7ad9 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 159b0a0dd211..94d9f7224aea 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -95,7 +95,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq) struct type86_hdr hdr; struct type86_fmt2_ext fmt2; struct CPRBX cprbx; - } __attribute__((packed)) *reply; + } __packed *reply; struct { struct type6_hdr hdr; struct CPRBX cprbx; @@ -104,7 +104,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq) char rule[8]; short int verb_length; short int key_length; - } __packed * msg; + } __packed *msg; int rc, i; ap_init_message(&ap_msg); @@ -223,6 +223,7 @@ static struct ap_driver zcrypt_pcixcc_card_driver = { .probe = zcrypt_pcixcc_card_probe, .remove = zcrypt_pcixcc_card_remove, .ids = zcrypt_pcixcc_card_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; /** @@ -286,6 +287,7 @@ static struct ap_driver zcrypt_pcixcc_queue_driver = { .suspend = ap_queue_suspend, .resume = ap_queue_resume, .ids = zcrypt_pcixcc_queue_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; int __init zcrypt_pcixcc_init(void) diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index d678a3af83a7..cf73a0f91e9c 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index 91a52f268353..8df82c6ef66e 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -38,18 +38,18 @@ * Device attributes common for all crypto queue devices. */ -static ssize_t zcrypt_queue_online_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t online_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_queue *zq = to_ap_queue(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", zq->online); } -static ssize_t zcrypt_queue_online_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct zcrypt_queue *zq = to_ap_queue(dev)->private; struct zcrypt_card *zc = zq->zcard; @@ -72,19 +72,18 @@ static ssize_t zcrypt_queue_online_store(struct device *dev, return count; } -static DEVICE_ATTR(online, 0644, zcrypt_queue_online_show, - zcrypt_queue_online_store); +static DEVICE_ATTR_RW(online); -static ssize_t zcrypt_queue_load_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t load_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_queue *zq = to_ap_queue(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); } -static DEVICE_ATTR(load, 0444, zcrypt_queue_load_show, NULL); +static DEVICE_ATTR_RO(load); static struct attribute *zcrypt_queue_attrs[] = { &dev_attr_online.attr, diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index 0e56f1eb05dc..eaf36ccf58db 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -423,19 +423,11 @@ static int osd_probe(struct device *dev) if (scsi_device->type != TYPE_OSD) return -ENODEV; - do { - if (!ida_pre_get(&osd_minor_ida, GFP_KERNEL)) - return -ENODEV; - - error = ida_get_new(&osd_minor_ida, &minor); - } while (error == -EAGAIN); - - if (error) - return error; - if (minor >= SCSI_OSD_MAX_MINOR) { - error = -EBUSY; - goto err_retract_minor; - } + minor = ida_alloc_max(&osd_minor_ida, SCSI_OSD_MAX_MINOR, GFP_KERNEL); + if (minor == -ENOSPC) + return -EBUSY; + if (minor < 0) + return -ENODEV; error = -ENOMEM; oud = kzalloc(sizeof(*oud), GFP_KERNEL); @@ -499,7 +491,7 @@ static int osd_probe(struct device *dev) err_free_osd: put_device(&oud->class_dev); err_retract_minor: - ida_remove(&osd_minor_ida, minor); + ida_free(&osd_minor_ida, minor); return error; } @@ -514,7 +506,7 @@ static int osd_remove(struct device *dev) } cdev_device_del(&oud->cdev, &oud->class_dev); - ida_remove(&osd_minor_ida, oud->minor); + ida_free(&osd_minor_ida, oud->minor); put_device(&oud->class_dev); return 0; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a58cee7a85f2..b79b366a94f7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -123,7 +123,6 @@ static void scsi_disk_release(struct device *cdev); static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); static void sd_print_result(const struct scsi_disk *, const char *, int); -static DEFINE_SPINLOCK(sd_index_lock); static DEFINE_IDA(sd_index_ida); /* This semaphore is used to mediate the 0->1 reference get in the @@ -3340,16 +3339,8 @@ static int sd_probe(struct device *dev) if (!gd) goto out_free; - do { - if (!ida_pre_get(&sd_index_ida, GFP_KERNEL)) - goto out_put; - - spin_lock(&sd_index_lock); - error = ida_get_new(&sd_index_ida, &index); - spin_unlock(&sd_index_lock); - } while (error == -EAGAIN); - - if (error) { + index = ida_alloc(&sd_index_ida, GFP_KERNEL); + if (index < 0) { sdev_printk(KERN_WARNING, sdp, "sd_probe: memory exhausted.\n"); goto out_put; } @@ -3393,9 +3384,7 @@ static int sd_probe(struct device *dev) return 0; out_free_index: - spin_lock(&sd_index_lock); - ida_remove(&sd_index_ida, index); - spin_unlock(&sd_index_lock); + ida_free(&sd_index_ida, index); out_put: put_disk(gd); out_free: @@ -3460,9 +3449,7 @@ static void scsi_disk_release(struct device *dev) struct scsi_disk *sdkp = to_scsi_disk(dev); struct gendisk *disk = sdkp->disk; - spin_lock(&sd_index_lock); - ida_remove(&sd_index_ida, sdkp->index); - spin_unlock(&sd_index_lock); + ida_free(&sd_index_ida, sdkp->index); disk->private_data = NULL; put_disk(disk); diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c index dcf8c8065508..a5577dd5eb08 100644 --- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c +++ b/drivers/soc/bcm/brcmstb/pm/pm-arm.c @@ -628,10 +628,26 @@ static const struct of_device_id ddr_shimphy_dt_ids[] = { static const struct of_device_id brcmstb_memc_of_match[] = { { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1", + .data = &ddr_seq, + }, + { .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2", .data = &ddr_seq_b22, }, { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3", + .data = &ddr_seq_b22, + }, + { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0", + .data = &ddr_seq_b22, + }, + { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1", + .data = &ddr_seq_b22, + }, + { .compatible = "brcm,brcmstb-memc-ddr", .data = &ddr_seq, }, diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig index 7a9fb9baa66d..8f80e8bbf29e 100644 --- a/drivers/soc/fsl/Kconfig +++ b/drivers/soc/fsl/Kconfig @@ -1,7 +1,9 @@ # -# Freescale SOC drivers +# NXP/Freescale QorIQ series SOC drivers # +menu "NXP/Freescale QorIQ SoC drivers" + source "drivers/soc/fsl/qbman/Kconfig" source "drivers/soc/fsl/qe/Kconfig" @@ -16,3 +18,14 @@ config FSL_GUTS Initially only reading SVR and registering soc device are supported. Other guts accesses, such as reading RCW, should eventually be moved into this driver as well. + +config FSL_MC_DPIO + tristate "QorIQ DPAA2 DPIO driver" + depends on FSL_MC_BUS + help + Driver for the DPAA2 DPIO object. A DPIO provides queue and + buffer management facilities for software to interact with + other DPAA2 objects. This driver does not expose the DPIO + objects individually, but groups them under a service layer + API. +endmenu diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile index 44b3bebef24a..803ef1bfb5ff 100644 --- a/drivers/soc/fsl/Makefile +++ b/drivers/soc/fsl/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_FSL_DPAA) += qbman/ obj-$(CONFIG_QUICC_ENGINE) += qe/ obj-$(CONFIG_CPM) += qe/ obj-$(CONFIG_FSL_GUTS) += guts.o +obj-$(CONFIG_FSL_MC_DPIO) += dpio/ diff --git a/drivers/staging/fsl-mc/bus/dpio/Makefile b/drivers/soc/fsl/dpio/Makefile index b9ff24c76582..b9ff24c76582 100644 --- a/drivers/staging/fsl-mc/bus/dpio/Makefile +++ b/drivers/soc/fsl/dpio/Makefile diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h b/drivers/soc/fsl/dpio/dpio-cmd.h index ab8f82ee7ee5..ab8f82ee7ee5 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h +++ b/drivers/soc/fsl/dpio/dpio-cmd.h diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 11a90a90d827..b60b77bfaffa 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -16,7 +16,7 @@ #include <linux/io.h> #include <linux/fsl/mc.h> -#include "../../include/dpaa2-io.h" +#include <soc/fsl/dpaa2-io.h> #include "qbman-portal.h" #include "dpio.h" diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 14ed2beb7432..9b17f72349ed 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -6,7 +6,7 @@ */ #include <linux/types.h> #include <linux/fsl/mc.h> -#include "../../include/dpaa2-io.h" +#include <soc/fsl/dpaa2-io.h> #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.c b/drivers/soc/fsl/dpio/dpio.c index ff37c80e11a0..ff37c80e11a0 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio.c +++ b/drivers/soc/fsl/dpio/dpio.c diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.h b/drivers/soc/fsl/dpio/dpio.h index 49194c8e45f1..49194c8e45f1 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio.h +++ b/drivers/soc/fsl/dpio/dpio.h diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c index 116fafb28640..cf1d448ea468 100644 --- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c +++ b/drivers/soc/fsl/dpio/qbman-portal.c @@ -8,7 +8,7 @@ #include <asm/cacheflush.h> #include <linux/io.h> #include <linux/slab.h> -#include "../../include/dpaa2-global.h" +#include <soc/fsl/dpaa2-global.h> #include "qbman-portal.h" diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h b/drivers/soc/fsl/dpio/qbman-portal.h index 69db3c818742..89d1dd9969b6 100644 --- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h +++ b/drivers/soc/fsl/dpio/qbman-portal.h @@ -7,7 +7,7 @@ #ifndef __FSL_QBMAN_PORTAL_H #define __FSL_QBMAN_PORTAL_H -#include "../../include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-fd.h> struct dpaa2_dq; struct qbman_swp; diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig index fb4e6bf0a0c4..d570cb5fd381 100644 --- a/drivers/soc/fsl/qbman/Kconfig +++ b/drivers/soc/fsl/qbman/Kconfig @@ -1,5 +1,5 @@ menuconfig FSL_DPAA - bool "Freescale DPAA 1.x support" + bool "QorIQ DPAA1 framework support" depends on (FSL_SOC_BOOKE || ARCH_LAYERSCAPE) select GENERIC_ALLOCATOR help diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index 73a2e08b47ef..fabba17e9d65 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -3,7 +3,7 @@ # config QUICC_ENGINE - bool "Freescale QUICC Engine (QE) Support" + bool "QUICC Engine (QE) framework support" depends on FSL_SOC && PPC32 select GENERIC_ALLOCATOR select CRC32 diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 3b27075c21a7..819bed0f5667 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -83,6 +83,33 @@ static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) spin_unlock_irqrestore(&qe_gc->lock, flags); } +static void qe_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); + struct qe_pio_regs __iomem *regs = mm_gc->regs; + unsigned long flags; + int i; + + spin_lock_irqsave(&qe_gc->lock, flags); + + for (i = 0; i < gc->ngpio; i++) { + if (*mask == 0) + break; + if (__test_and_clear_bit(i, mask)) { + if (test_bit(i, bits)) + qe_gc->cpdata |= (1U << (QE_PIO_PINS - 1 - i)); + else + qe_gc->cpdata &= ~(1U << (QE_PIO_PINS - 1 - i)); + } + } + + out_be32(®s->cpdata, qe_gc->cpdata); + + spin_unlock_irqrestore(&qe_gc->lock, flags); +} + static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); @@ -298,6 +325,7 @@ static int __init qe_add_gpiochips(void) gc->direction_output = qe_gpio_dir_out; gc->get = qe_gpio_get; gc->set = qe_gpio_set; + gc->set_multiple = qe_gpio_set_multiple; ret = of_mm_gpiochip_add_data(np, mm_gc, qe_gc); if (ret) diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 546960a18d60..b3da635970ea 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -54,7 +54,6 @@ struct imx_pm_domain { unsigned int reg_offs; signed char cntr_pdn_bit; unsigned int ipg_rate_mhz; - unsigned int flags; }; static inline struct imx_pm_domain * @@ -69,9 +68,6 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd) int iso, iso2sw; u32 val; - if (pd->flags & PGC_DOMAIN_FLAG_NO_PD) - return -EBUSY; - /* Read ISO and ISO2SW power down delays */ regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); iso = val & 0x3f; @@ -295,26 +291,31 @@ static struct imx_pm_domain imx_gpc_domains[] = { struct imx_gpc_dt_data { int num_domains; bool err009619_present; + bool err006287_present; }; static const struct imx_gpc_dt_data imx6q_dt_data = { .num_domains = 2, .err009619_present = false, + .err006287_present = false, }; static const struct imx_gpc_dt_data imx6qp_dt_data = { .num_domains = 2, .err009619_present = true, + .err006287_present = false, }; static const struct imx_gpc_dt_data imx6sl_dt_data = { .num_domains = 3, .err009619_present = false, + .err006287_present = true, }; static const struct imx_gpc_dt_data imx6sx_dt_data = { .num_domains = 4, .err009619_present = false, + .err006287_present = false, }; static const struct of_device_id imx_gpc_dt_ids[] = { @@ -434,8 +435,13 @@ static int imx_gpc_probe(struct platform_device *pdev) /* Disable PU power down in normal operation if ERR009619 is present */ if (of_id_data->err009619_present) - imx_gpc_domains[GPC_PGC_DOMAIN_PU].flags |= - PGC_DOMAIN_FLAG_NO_PD; + imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |= + GENPD_FLAG_ALWAYS_ON; + + /* Keep DISP always on if ERR006287 is present */ + if (of_id_data->err006287_present) + imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |= + GENPD_FLAG_ALWAYS_ON; if (!pgc_node) { ret = imx_gpc_old_dt_init(&pdev->dev, regmap, diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 2afae64061d8..4e931fdf4d09 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -146,6 +146,21 @@ static const u32 mt6397_regs[] = { [PWRAP_DEW_CIPHER_SWRST] = 0xbc24, }; +static const u32 mt6351_regs[] = { + [PWRAP_DEW_DIO_EN] = 0x02F2, + [PWRAP_DEW_READ_TEST] = 0x02F4, + [PWRAP_DEW_WRITE_TEST] = 0x02F6, + [PWRAP_DEW_CRC_EN] = 0x02FA, + [PWRAP_DEW_CRC_VAL] = 0x02FC, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302, + [PWRAP_DEW_CIPHER_EN] = 0x0304, + [PWRAP_DEW_CIPHER_RDY] = 0x0306, + [PWRAP_DEW_CIPHER_MODE] = 0x0308, + [PWRAP_DEW_CIPHER_SWRST] = 0x030A, + [PWRAP_DEW_RDDMY_NO] = 0x030C, +}; + enum pwrap_regs { PWRAP_MUX_SEL, PWRAP_WRAP_EN, @@ -366,6 +381,39 @@ static int mt2701_regs[] = { [PWRAP_ADC_RDATA_ADDR2] = 0x154, }; +static int mt6797_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xC, + [PWRAP_RDDMY] = 0x10, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1C, + [PWRAP_CSLEXT_START] = 0x20, + [PWRAP_CSLEXT_END] = 0x24, + [PWRAP_STAUPD_PRD] = 0x28, + [PWRAP_HARB_HPRIO] = 0x50, + [PWRAP_HIPRIO_ARB_EN] = 0x54, + [PWRAP_MAN_EN] = 0x60, + [PWRAP_MAN_CMD] = 0x64, + [PWRAP_WACS0_EN] = 0x70, + [PWRAP_WACS1_EN] = 0x84, + [PWRAP_WACS2_EN] = 0x98, + [PWRAP_INIT_DONE2] = 0x9C, + [PWRAP_WACS2_CMD] = 0xA0, + [PWRAP_WACS2_RDATA] = 0xA4, + [PWRAP_WACS2_VLDCLR] = 0xA8, + [PWRAP_INT_EN] = 0xC0, + [PWRAP_INT_FLG_RAW] = 0xC4, + [PWRAP_INT_FLG] = 0xC8, + [PWRAP_INT_CLR] = 0xCC, + [PWRAP_TIMER_EN] = 0xF4, + [PWRAP_WDT_UNIT] = 0xFC, + [PWRAP_WDT_SRC_EN] = 0x100, + [PWRAP_DCM_EN] = 0x1CC, + [PWRAP_DCM_DBC_PRD] = 0x1D4, +}; + static int mt7622_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, @@ -635,12 +683,14 @@ static int mt8135_regs[] = { enum pmic_type { PMIC_MT6323, + PMIC_MT6351, PMIC_MT6380, PMIC_MT6397, }; enum pwrap_type { PWRAP_MT2701, + PWRAP_MT6797, PWRAP_MT7622, PWRAP_MT8135, PWRAP_MT8173, @@ -1067,6 +1117,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) pwrap_writel(wrp, 1, PWRAP_CIPHER_START); break; case PWRAP_MT2701: + case PWRAP_MT6797: case PWRAP_MT8173: pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); break; @@ -1080,8 +1131,6 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0); pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1); pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2); - pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], 0x1); - pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], 0x1); switch (wrp->slave->type) { case PMIC_MT6397: @@ -1091,6 +1140,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) 0x1); break; case PMIC_MT6323: + case PMIC_MT6351: pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN], 0x1); break; @@ -1367,6 +1417,15 @@ static const struct pwrap_slv_type pmic_mt6397 = { .pwrap_write = pwrap_write16, }; +static const struct pwrap_slv_type pmic_mt6351 = { + .dew_regs = mt6351_regs, + .type = PMIC_MT6351, + .regmap = &pwrap_regmap_config16, + .caps = 0, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + static const struct of_device_id of_slave_match_tbl[] = { { .compatible = "mediatek,mt6323", @@ -1381,6 +1440,9 @@ static const struct of_device_id of_slave_match_tbl[] = { .compatible = "mediatek,mt6397", .data = &pmic_mt6397, }, { + .compatible = "mediatek,mt6351", + .data = &pmic_mt6351, + }, { /* sentinel */ } }; @@ -1398,6 +1460,18 @@ static const struct pmic_wrapper_type pwrap_mt2701 = { .init_soc_specific = pwrap_mt2701_init_soc_specific, }; +static const struct pmic_wrapper_type pwrap_mt6797 = { + .regs = mt6797_regs, + .type = PWRAP_MT6797, + .arb_en_all = 0x01fff, + .int_en_all = 0xffffffc6, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .has_bridge = 0, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + static const struct pmic_wrapper_type pwrap_mt7622 = { .regs = mt7622_regs, .type = PWRAP_MT7622, @@ -1439,6 +1513,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = { .compatible = "mediatek,mt2701-pwrap", .data = &pwrap_mt2701, }, { + .compatible = "mediatek,mt6797-pwrap", + .data = &pwrap_mt6797, + }, { .compatible = "mediatek,mt7622-pwrap", .data = &pwrap_mt7622, }, { diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 7dc0f20d7907..c37b0803c1b6 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -18,6 +18,9 @@ obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o +ifdef CONFIG_SMP +obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o +endif # Family obj-$(CONFIG_RST_RCAR) += rcar-rst.o diff --git a/drivers/soc/renesas/r9a06g032-smp.c b/drivers/soc/renesas/r9a06g032-smp.c new file mode 100644 index 000000000000..a1926e8d73f2 --- /dev/null +++ b/drivers/soc/renesas/r9a06g032-smp.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R9A06G032 Second CA7 enabler. + * + * Copyright (C) 2018 Renesas Electronics Europe Limited + * + * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com> + * Derived from actions,s500-smp + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/smp.h> + +/* + * The second CPU is parked in ROM at boot time. It requires waking it after + * writing an address into the BOOTADDR register of sysctrl. + * + * So the default value of the "cpu-release-addr" corresponds to BOOTADDR... + * + * *However* the BOOTADDR register is not available when the kernel + * starts in NONSEC mode. + * + * So for NONSEC mode, the bootloader re-parks the second CPU into a pen + * in SRAM, and changes the "cpu-release-addr" of linux's DT to a SRAM address, + * which is not restricted. + */ + +static void __iomem *cpu_bootaddr; + +static DEFINE_SPINLOCK(cpu_lock); + +static int +r9a06g032_smp_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + if (!cpu_bootaddr) + return -ENODEV; + + spin_lock(&cpu_lock); + + writel(__pa_symbol(secondary_startup), cpu_bootaddr); + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + spin_unlock(&cpu_lock); + + return 0; +} + +static void __init r9a06g032_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *dn; + int ret = -EINVAL, dns; + u32 bootaddr; + + dn = of_get_cpu_node(1, NULL); + if (!dn) { + pr_err("CPU#1: missing device tree node\n"); + return; + } + /* + * Determine the address from which the CPU is polling. + * The bootloader *does* change this property. + * Note: The property can be either 64 or 32 bits, so handle both cases + */ + if (of_find_property(dn, "cpu-release-addr", &dns)) { + if (dns == sizeof(u64)) { + u64 temp; + + ret = of_property_read_u64(dn, + "cpu-release-addr", &temp); + bootaddr = temp; + } else { + ret = of_property_read_u32(dn, + "cpu-release-addr", + &bootaddr); + } + } + of_node_put(dn); + if (ret) { + pr_err("CPU#1: invalid cpu-release-addr property\n"); + return; + } + pr_info("CPU#1: cpu-release-addr %08x\n", bootaddr); + + cpu_bootaddr = ioremap(bootaddr, sizeof(bootaddr)); +} + +static const struct smp_operations r9a06g032_smp_ops __initconst = { + .smp_prepare_cpus = r9a06g032_smp_prepare_cpus, + .smp_boot_secondary = r9a06g032_smp_boot_secondary, +}; + +CPU_METHOD_OF_DECLARE(r9a06g032_smp, + "renesas,r9a06g032-smp", &r9a06g032_smp_ops); diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 50d03d8b4f9a..029188e8be6e 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -58,6 +58,12 @@ #define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */ +struct rcar_sysc_ch { + u16 chan_offs; + u8 chan_bit; + u8 isr_bit; +}; + static void __iomem *rcar_sysc_base; static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */ @@ -143,12 +149,12 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) return ret; } -int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) +static int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) { return rcar_sysc_power(sysc_ch, false); } -int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) +static int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) { return rcar_sysc_power(sysc_ch, true); } @@ -315,6 +321,8 @@ struct rcar_pm_domains { struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1]; }; +static struct genpd_onecell_data *rcar_sysc_onecell_data; + static int __init rcar_sysc_pd_init(void) { const struct rcar_sysc_info *info; @@ -326,9 +334,6 @@ static int __init rcar_sysc_pd_init(void) unsigned int i; int error; - if (rcar_sysc_base) - return 0; - np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match); if (!np) return -ENODEV; @@ -361,6 +366,7 @@ static int __init rcar_sysc_pd_init(void) domains->onecell_data.domains = domains->domains; domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); + rcar_sysc_onecell_data = &domains->onecell_data; for (i = 0, syscier = 0; i < info->num_areas; i++) syscier |= BIT(info->areas[i].isr_bit); @@ -448,27 +454,39 @@ void __init rcar_sysc_nullify(struct rcar_sysc_area *areas, } } -void __init rcar_sysc_init(phys_addr_t base, u32 syscier) +#ifdef CONFIG_ARCH_R8A7779 +static int rcar_sysc_power_cpu(unsigned int idx, bool on) { - u32 syscimr; + struct generic_pm_domain *genpd; + struct rcar_sysc_pd *pd; + unsigned int i; - if (!rcar_sysc_pd_init()) - return; + if (!rcar_sysc_onecell_data) + return -ENODEV; - rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE); + for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) { + genpd = rcar_sysc_onecell_data->domains[i]; + if (!genpd) + continue; - /* - * Mask all interrupt sources to prevent the CPU from receiving them. - * Make sure not to clear reserved bits that were set before. - */ - syscimr = ioread32(rcar_sysc_base + SYSCIMR); - syscimr |= syscier; - pr_debug("%s: syscimr = 0x%08x\n", __func__, syscimr); - iowrite32(syscimr, rcar_sysc_base + SYSCIMR); + pd = to_rcar_pd(genpd); + if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx) + continue; - /* - * SYSC needs all interrupt sources enabled to control power. - */ - pr_debug("%s: syscier = 0x%08x\n", __func__, syscier); - iowrite32(syscier, rcar_sysc_base + SYSCIER); + return on ? rcar_sysc_power_up(&pd->ch) + : rcar_sysc_power_down(&pd->ch); + } + + return -ENOENT; +} + +int rcar_sysc_power_down_cpu(unsigned int cpu) +{ + return rcar_sysc_power_cpu(cpu, false); +} + +int rcar_sysc_power_up_cpu(unsigned int cpu) +{ + return rcar_sysc_power_cpu(cpu, true); } +#endif /* CONFIG_ARCH_R8A7779 */ diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 882be5ed7e84..b4b0f3480bd3 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -17,6 +17,7 @@ #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/soc/sunxi/sunxi_sram.h> @@ -63,6 +64,12 @@ static struct sunxi_sram_desc sun4i_a10_sram_a3_a4 = { SUNXI_SRAM_MAP(1, 1, "emac")), }; +static struct sunxi_sram_desc sun4i_a10_sram_c1 = { + .data = SUNXI_SRAM_DATA("C1", 0x0, 0x0, 31, + SUNXI_SRAM_MAP(0, 0, "cpu"), + SUNXI_SRAM_MAP(0x7fffffff, 1, "ve")), +}; + static struct sunxi_sram_desc sun4i_a10_sram_d = { .data = SUNXI_SRAM_DATA("D", 0x4, 0x0, 1, SUNXI_SRAM_MAP(0, 0, "cpu"), @@ -81,6 +88,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = { .data = &sun4i_a10_sram_a3_a4.data, }, { + .compatible = "allwinner,sun4i-a10-sram-c1", + .data = &sun4i_a10_sram_c1.data, + }, + { .compatible = "allwinner,sun4i-a10-sram-d", .data = &sun4i_a10_sram_d.data, }, @@ -281,13 +292,51 @@ int sunxi_sram_release(struct device *dev) } EXPORT_SYMBOL(sunxi_sram_release); +struct sunxi_sramc_variant { + bool has_emac_clock; +}; + +static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = { + /* Nothing special */ +}; + +static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = { + .has_emac_clock = true, +}; + +#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30 +static bool sunxi_sram_regmap_accessible_reg(struct device *dev, + unsigned int reg) +{ + if (reg == SUNXI_SRAM_EMAC_CLOCK_REG) + return true; + return false; +} + +static struct regmap_config sunxi_sram_emac_clock_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + /* last defined register */ + .max_register = SUNXI_SRAM_EMAC_CLOCK_REG, + /* other devices have no business accessing other registers */ + .readable_reg = sunxi_sram_regmap_accessible_reg, + .writeable_reg = sunxi_sram_regmap_accessible_reg, +}; + static int sunxi_sram_probe(struct platform_device *pdev) { struct resource *res; struct dentry *d; + struct regmap *emac_clock; + const struct sunxi_sramc_variant *variant; sram_dev = &pdev->dev; + variant = of_device_get_match_data(&pdev->dev); + if (!variant) + return -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) @@ -300,12 +349,46 @@ static int sunxi_sram_probe(struct platform_device *pdev) if (!d) return -ENOMEM; + if (variant->has_emac_clock) { + emac_clock = devm_regmap_init_mmio(&pdev->dev, base, + &sunxi_sram_emac_clock_regmap); + + if (IS_ERR(emac_clock)) + return PTR_ERR(emac_clock); + } + return 0; } static const struct of_device_id sunxi_sram_dt_match[] = { - { .compatible = "allwinner,sun4i-a10-sram-controller" }, - { .compatible = "allwinner,sun50i-a64-sram-controller" }, + { + .compatible = "allwinner,sun4i-a10-sram-controller", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun4i-a10-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun5i-a13-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun8i-a23-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun8i-h3-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun50i-a64-sram-controller", + .data = &sun50i_a64_sramc_variant, + }, + { + .compatible = "allwinner,sun50i-a64-system-control", + .data = &sun50i_a64_sramc_variant, + }, { }, }; MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match); diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index 92770d84a288..be4570baad96 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -1,3 +1,17 @@ +# 64-bit ARM SoCs from TI +if ARM64 + +if ARCH_K3 + +config ARCH_K3_AM6_SOC + bool "K3 AM6 SoC" + help + Enable support for TI's AM6 SoC Family support + +endif + +endif + # # TI SOC drivers # diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 652739c7f718..d0dab323651f 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -41,6 +41,8 @@ static struct am33xx_pm_sram_addr *pm_sram; static struct device *pm33xx_dev; static struct wkup_m3_ipc *m3_ipc; +static unsigned long suspend_wfi_flags; + static u32 sram_suspend_address(unsigned long addr) { return ((unsigned long)am33xx_do_wfi_sram + @@ -53,7 +55,7 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) int i, ret = 0; ret = pm_ops->soc_suspend((unsigned long)suspend_state, - am33xx_do_wfi_sram); + am33xx_do_wfi_sram, suspend_wfi_flags); if (ret) { dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); @@ -227,6 +229,7 @@ static int am33xx_push_sram_idle(void) ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; ro_sram_data.amx3_pm_sram_data_phys = gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); + ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr(); /* Save physical address to calculate resume offset during pm init */ am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, @@ -310,6 +313,17 @@ static int am33xx_pm_probe(struct platform_device *pdev) suspend_set_ops(&am33xx_pm_ops); #endif /* CONFIG_SUSPEND */ + /* + * For a system suspend we must flush the caches, we want + * the DDR in self-refresh, we want to save the context + * of the EMIF, and we want the wkup_m3 to handle low-power + * transition. + */ + suspend_wfi_flags |= WFI_FLAG_FLUSH_CACHE; + suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; + suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; + suspend_wfi_flags |= WFI_FLAG_WAKE_M3; + ret = pm_ops->init(); if (ret) { dev_err(dev, "Unable to call core pm init!\n"); diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 369aef5e7228..f5cb8c0af09f 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -46,6 +46,7 @@ #define M3_BASELINE_VERSION 0x191 #define M3_STATUS_RESP_MASK (0xffff << 16) #define M3_FW_VERSION_MASK 0xffff +#define M3_WAKE_SRC_MASK 0xff #define M3_STATE_UNKNOWN 0 #define M3_STATE_RESET 1 @@ -55,6 +56,23 @@ static struct wkup_m3_ipc *m3_ipc_state; +static const struct wkup_m3_wakeup_src wakeups[] = { + {.irq_nr = 35, .src = "USB0_PHY"}, + {.irq_nr = 36, .src = "USB1_PHY"}, + {.irq_nr = 40, .src = "I2C0"}, + {.irq_nr = 41, .src = "RTC Timer"}, + {.irq_nr = 42, .src = "RTC Alarm"}, + {.irq_nr = 43, .src = "Timer0"}, + {.irq_nr = 44, .src = "Timer1"}, + {.irq_nr = 45, .src = "UART"}, + {.irq_nr = 46, .src = "GPIO0"}, + {.irq_nr = 48, .src = "MPU_WAKE"}, + {.irq_nr = 49, .src = "WDT0"}, + {.irq_nr = 50, .src = "WDT1"}, + {.irq_nr = 51, .src = "ADC_TSC"}, + {.irq_nr = 0, .src = "Unknown"}, +}; + static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc) { writel(AM33XX_M3_TXEV_ACK, @@ -329,12 +347,45 @@ static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc) return 0; } +/** + * wkup_m3_request_wake_src - Get the wakeup source info passed from wkup_m3 + * @m3_ipc: Pointer to wkup_m3_ipc context + */ +static const char *wkup_m3_request_wake_src(struct wkup_m3_ipc *m3_ipc) +{ + unsigned int wakeup_src_idx; + int j, val; + + val = wkup_m3_ctrl_ipc_read(m3_ipc, 6); + + wakeup_src_idx = val & M3_WAKE_SRC_MASK; + + for (j = 0; j < ARRAY_SIZE(wakeups) - 1; j++) { + if (wakeups[j].irq_nr == wakeup_src_idx) + return wakeups[j].src; + } + return wakeups[j].src; +} + +/** + * wkup_m3_set_rtc_only - Set the rtc_only flag + * @wkup_m3_wakeup: struct wkup_m3_wakeup_src * gets assigned the + * wakeup src value + */ +static void wkup_m3_set_rtc_only(struct wkup_m3_ipc *m3_ipc) +{ + if (m3_ipc_state) + m3_ipc_state->is_rtc_only = true; +} + static struct wkup_m3_ipc_ops ipc_ops = { .set_mem_type = wkup_m3_set_mem_type, .set_resume_address = wkup_m3_set_resume_address, .prepare_low_power = wkup_m3_prepare_low_power, .finish_low_power = wkup_m3_finish_low_power, .request_pm_status = wkup_m3_request_pm_status, + .request_wake_src = wkup_m3_request_wake_src, + .set_rtc_only = wkup_m3_set_rtc_only, }; /** @@ -484,6 +535,30 @@ static int wkup_m3_ipc_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused wkup_m3_ipc_suspend(struct device *dev) +{ + /* + * Nothing needs to be done on suspend even with rtc_only flag set + */ + return 0; +} + +static int __maybe_unused wkup_m3_ipc_resume(struct device *dev) +{ + if (m3_ipc_state->is_rtc_only) { + rproc_shutdown(m3_ipc_state->rproc); + rproc_boot(m3_ipc_state->rproc); + } + + m3_ipc_state->is_rtc_only = false; + + return 0; +} + +static const struct dev_pm_ops wkup_m3_ipc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(wkup_m3_ipc_suspend, wkup_m3_ipc_resume) +}; + static const struct of_device_id wkup_m3_ipc_of_match[] = { { .compatible = "ti,am3352-wkup-m3-ipc", }, { .compatible = "ti,am4372-wkup-m3-ipc", }, @@ -497,6 +572,7 @@ static struct platform_driver wkup_m3_ipc_driver = { .driver = { .name = "wkup_m3_ipc", .of_match_table = wkup_m3_ipc_of_match, + .pm = &wkup_m3_ipc_pm_ops, }, }; diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 396fb3d56398..1abf76be2aa8 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -90,8 +90,6 @@ source "drivers/staging/clocking-wizard/Kconfig" source "drivers/staging/fbtft/Kconfig" -source "drivers/staging/fsl-mc/Kconfig" - source "drivers/staging/fsl-dpaa2/Kconfig" source "drivers/staging/wilc1000/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ad7b4ca412ef..ab0cbe8815b1 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ obj-$(CONFIG_UNISYSSPAR) += unisys/ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ obj-$(CONFIG_FB_TFT) += fbtft/ -obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ obj-$(CONFIG_FSL_DPAA2) += fsl-dpaa2/ obj-$(CONFIG_WILC1000) += wilc1000/ obj-$(CONFIG_MOST) += most/ diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index e2dac44eccbe..9329fcad95ac 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -426,7 +426,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_format(fd, dpaa2_fd_sg); dpaa2_fd_set_addr(fd, addr); dpaa2_fd_set_len(fd, skb->len); - dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1); + dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1); if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) enable_tx_tstamp(fd, sgt_buf); @@ -479,7 +479,7 @@ static int build_single_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_offset(fd, (u16)(skb->data - buffer_start)); dpaa2_fd_set_len(fd, skb->len); dpaa2_fd_set_format(fd, dpaa2_fd_single); - dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1); + dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1); if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) enable_tx_tstamp(fd, buffer_start); diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h index 506466778b2c..d54cb0b99d08 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h @@ -10,8 +10,8 @@ #include <linux/if_vlan.h> #include <linux/fsl/mc.h> -#include "../../fsl-mc/include/dpaa2-io.h" -#include "../../fsl-mc/include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-io.h> +#include <soc/fsl/dpaa2-fd.h> #include "dpni.h" #include "dpni-cmd.h" @@ -97,21 +97,13 @@ struct dpaa2_eth_swa { #define DPAA2_FD_FRC_FAICFDV 0x0400 /* Error bits in FD CTRL */ -#define DPAA2_FD_CTRL_UFD 0x00000004 -#define DPAA2_FD_CTRL_SBE 0x00000008 -#define DPAA2_FD_CTRL_FSE 0x00000020 -#define DPAA2_FD_CTRL_FAERR 0x00000040 - -#define DPAA2_FD_RX_ERR_MASK (DPAA2_FD_CTRL_SBE | \ - DPAA2_FD_CTRL_FAERR) -#define DPAA2_FD_TX_ERR_MASK (DPAA2_FD_CTRL_UFD | \ - DPAA2_FD_CTRL_SBE | \ - DPAA2_FD_CTRL_FSE | \ - DPAA2_FD_CTRL_FAERR) +#define DPAA2_FD_RX_ERR_MASK (FD_CTRL_SBE | FD_CTRL_FAERR) +#define DPAA2_FD_TX_ERR_MASK (FD_CTRL_UFD | \ + FD_CTRL_SBE | \ + FD_CTRL_FSE | \ + FD_CTRL_FAERR) /* Annotation bits in FD CTRL */ -#define DPAA2_FD_CTRL_PTA 0x00800000 -#define DPAA2_FD_CTRL_PTV1 0x00400000 #define DPAA2_FD_CTRL_ASAL 0x00020000 /* ASAL = 128B */ /* Frame annotation status */ diff --git a/drivers/staging/fsl-mc/Kconfig b/drivers/staging/fsl-mc/Kconfig deleted file mode 100644 index 3002229bec1b..000000000000 --- a/drivers/staging/fsl-mc/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -source "drivers/staging/fsl-mc/bus/Kconfig" diff --git a/drivers/staging/fsl-mc/Makefile b/drivers/staging/fsl-mc/Makefile deleted file mode 100644 index 14683889dabd..000000000000 --- a/drivers/staging/fsl-mc/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Freescale Management Complex (MC) bus drivers -obj-$(CONFIG_FSL_MC_BUS) += bus/ diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig deleted file mode 100644 index 342453035269..000000000000 --- a/drivers/staging/fsl-mc/bus/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# DPAA2 fsl-mc bus -# -# Copyright (C) 2014-2016 Freescale Semiconductor, Inc. -# - -config FSL_MC_DPIO - tristate "QorIQ DPAA2 DPIO driver" - depends on FSL_MC_BUS - help - Driver for the DPAA2 DPIO object. A DPIO provides queue and - buffer management facilities for software to interact with - other DPAA2 objects. This driver does not expose the DPIO - objects individually, but groups them under a service layer - API. diff --git a/drivers/staging/fsl-mc/bus/Makefile b/drivers/staging/fsl-mc/bus/Makefile deleted file mode 100644 index 21d8ebc8ce21..000000000000 --- a/drivers/staging/fsl-mc/bus/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Freescale Management Complex (MC) bus drivers -# -# Copyright (C) 2014 Freescale Semiconductor, Inc. -# - -# MC DPIO driver -obj-$(CONFIG_FSL_MC_DPIO) += dpio/ diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt deleted file mode 100644 index 72ba9da3d179..000000000000 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt +++ /dev/null @@ -1,135 +0,0 @@ -Copyright 2016 NXP - -Introduction ------------- - -A DPAA2 DPIO (Data Path I/O) is a hardware object that provides -interfaces to enqueue and dequeue frames to/from network interfaces -and other accelerators. A DPIO also provides hardware buffer -pool management for network interfaces. - -This document provides an overview the Linux DPIO driver, its -subcomponents, and its APIs. - -See Documentation/networking/dpaa2/overview.rst for a general overview of DPAA2 -and the general DPAA2 driver architecture in Linux. - -Driver Overview ---------------- - -The DPIO driver is bound to DPIO objects discovered on the fsl-mc bus and -provides services that: - A) allow other drivers, such as the Ethernet driver, to enqueue and dequeue - frames for their respective objects - B) allow drivers to register callbacks for data availability notifications - when data becomes available on a queue or channel - C) allow drivers to manage hardware buffer pools - -The Linux DPIO driver consists of 3 primary components-- - DPIO object driver-- fsl-mc driver that manages the DPIO object - DPIO service-- provides APIs to other Linux drivers for services - QBman portal interface-- sends portal commands, gets responses - - fsl-mc other - bus drivers - | | - +---+----+ +------+-----+ - |DPIO obj| |DPIO service| - | driver |---| (DPIO) | - +--------+ +------+-----+ - | - +------+-----+ - | QBman | - | portal i/f | - +------------+ - | - hardware - -The diagram below shows how the DPIO driver components fit with the other -DPAA2 Linux driver components: - +------------+ - | OS Network | - | Stack | - +------------+ +------------+ - | Allocator |. . . . . . . | Ethernet | - |(DPMCP,DPBP)| | (DPNI) | - +-.----------+ +---+---+----+ - . . ^ | - . . <data avail, | |<enqueue, - . . tx confirm> | | dequeue> - +-------------+ . | | - | DPRC driver | . +--------+ +------------+ - | (DPRC) | . . |DPIO obj| |DPIO service| - +----------+--+ | driver |-| (DPIO) | - | +--------+ +------+-----+ - |<dev add/remove> +------|-----+ - | | QBman | - +----+--------------+ | portal i/f | - | MC-bus driver | +------------+ - | | | - | /soc/fsl-mc | | - +-------------------+ | - | - =========================================|=========|======================== - +-+--DPIO---|-----------+ - | | | - | QBman Portal | - +-----------------------+ - - ============================================================================ - - -DPIO Object Driver (dpio-driver.c) ----------------------------------- - - The dpio-driver component registers with the fsl-mc bus to handle objects of - type "dpio". The implementation of probe() handles basic initialization - of the DPIO including mapping of the DPIO regions (the QBman SW portal) - and initializing interrupts and registering irq handlers. The dpio-driver - registers the probed DPIO with dpio-service. - -DPIO service (dpio-service.c, dpaa2-io.h) ------------------------------------------- - - The dpio service component provides queuing, notification, and buffers - management services to DPAA2 drivers, such as the Ethernet driver. A system - will typically allocate 1 DPIO object per CPU to allow queuing operations - to happen simultaneously across all CPUs. - - Notification handling - dpaa2_io_service_register() - dpaa2_io_service_deregister() - dpaa2_io_service_rearm() - - Queuing - dpaa2_io_service_pull_fq() - dpaa2_io_service_pull_channel() - dpaa2_io_service_enqueue_fq() - dpaa2_io_service_enqueue_qd() - dpaa2_io_store_create() - dpaa2_io_store_destroy() - dpaa2_io_store_next() - - Buffer pool management - dpaa2_io_service_release() - dpaa2_io_service_acquire() - -QBman portal interface (qbman-portal.c) ---------------------------------------- - - The qbman-portal component provides APIs to do the low level hardware - bit twiddling for operations such as: - -initializing Qman software portals - -building and sending portal commands - -portal interrupt configuration and processing - - The qbman-portal APIs are not public to other drivers, and are - only used by dpio-service. - -Other (dpaa2-fd.h, dpaa2-global.h) ----------------------------------- - - Frame descriptor and scatter-gather definitions and the APIs used to - manipulate them are defined in dpaa2-fd.h. - - Dequeue result struct and parsing APIs are defined in dpaa2-global.h. diff --git a/drivers/staging/fsl-mc/include/dpaa2-fd.h b/drivers/staging/fsl-mc/include/dpaa2-fd.h deleted file mode 100644 index b55b89ba4eda..000000000000 --- a/drivers/staging/fsl-mc/include/dpaa2-fd.h +++ /dev/null @@ -1,426 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016 NXP - * - */ -#ifndef __FSL_DPAA2_FD_H -#define __FSL_DPAA2_FD_H - -#include <linux/kernel.h> - -/** - * DOC: DPAA2 FD - Frame Descriptor APIs for DPAA2 - * - * Frame Descriptors (FDs) are used to describe frame data in the DPAA2. - * Frames can be enqueued and dequeued to Frame Queues (FQs) which are consumed - * by the various DPAA accelerators (WRIOP, SEC, PME, DCE) - * - * There are three types of frames: single, scatter gather, and frame lists. - * - * The set of APIs in this file must be used to create, manipulate and - * query Frame Descriptors. - */ - -/** - * struct dpaa2_fd - Struct describing FDs - * @words: for easier/faster copying the whole FD structure - * @addr: address in the FD - * @len: length in the FD - * @bpid: buffer pool ID - * @format_offset: format, offset, and short-length fields - * @frc: frame context - * @ctrl: control bits...including dd, sc, va, err, etc - * @flc: flow context address - * - * This structure represents the basic Frame Descriptor used in the system. - */ -struct dpaa2_fd { - union { - u32 words[8]; - struct dpaa2_fd_simple { - __le64 addr; - __le32 len; - __le16 bpid; - __le16 format_offset; - __le32 frc; - __le32 ctrl; - __le64 flc; - } simple; - }; -}; - -#define FD_SHORT_LEN_FLAG_MASK 0x1 -#define FD_SHORT_LEN_FLAG_SHIFT 14 -#define FD_SHORT_LEN_MASK 0x3FFFF -#define FD_OFFSET_MASK 0x0FFF -#define FD_FORMAT_MASK 0x3 -#define FD_FORMAT_SHIFT 12 -#define FD_BPID_MASK 0x3FFF -#define SG_SHORT_LEN_FLAG_MASK 0x1 -#define SG_SHORT_LEN_FLAG_SHIFT 14 -#define SG_SHORT_LEN_MASK 0x1FFFF -#define SG_OFFSET_MASK 0x0FFF -#define SG_FORMAT_MASK 0x3 -#define SG_FORMAT_SHIFT 12 -#define SG_BPID_MASK 0x3FFF -#define SG_FINAL_FLAG_MASK 0x1 -#define SG_FINAL_FLAG_SHIFT 15 - -enum dpaa2_fd_format { - dpaa2_fd_single = 0, - dpaa2_fd_list, - dpaa2_fd_sg -}; - -/** - * dpaa2_fd_get_addr() - get the addr field of frame descriptor - * @fd: the given frame descriptor - * - * Return the address in the frame descriptor. - */ -static inline dma_addr_t dpaa2_fd_get_addr(const struct dpaa2_fd *fd) -{ - return (dma_addr_t)le64_to_cpu(fd->simple.addr); -} - -/** - * dpaa2_fd_set_addr() - Set the addr field of frame descriptor - * @fd: the given frame descriptor - * @addr: the address needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_addr(struct dpaa2_fd *fd, dma_addr_t addr) -{ - fd->simple.addr = cpu_to_le64(addr); -} - -/** - * dpaa2_fd_get_frc() - Get the frame context in the frame descriptor - * @fd: the given frame descriptor - * - * Return the frame context field in the frame descriptor. - */ -static inline u32 dpaa2_fd_get_frc(const struct dpaa2_fd *fd) -{ - return le32_to_cpu(fd->simple.frc); -} - -/** - * dpaa2_fd_set_frc() - Set the frame context in the frame descriptor - * @fd: the given frame descriptor - * @frc: the frame context needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_frc(struct dpaa2_fd *fd, u32 frc) -{ - fd->simple.frc = cpu_to_le32(frc); -} - -/** - * dpaa2_fd_get_ctrl() - Get the control bits in the frame descriptor - * @fd: the given frame descriptor - * - * Return the control bits field in the frame descriptor. - */ -static inline u32 dpaa2_fd_get_ctrl(const struct dpaa2_fd *fd) -{ - return le32_to_cpu(fd->simple.ctrl); -} - -/** - * dpaa2_fd_set_ctrl() - Set the control bits in the frame descriptor - * @fd: the given frame descriptor - * @ctrl: the control bits to be set in the frame descriptor - */ -static inline void dpaa2_fd_set_ctrl(struct dpaa2_fd *fd, u32 ctrl) -{ - fd->simple.ctrl = cpu_to_le32(ctrl); -} - -/** - * dpaa2_fd_get_flc() - Get the flow context in the frame descriptor - * @fd: the given frame descriptor - * - * Return the flow context in the frame descriptor. - */ -static inline dma_addr_t dpaa2_fd_get_flc(const struct dpaa2_fd *fd) -{ - return (dma_addr_t)le64_to_cpu(fd->simple.flc); -} - -/** - * dpaa2_fd_set_flc() - Set the flow context field of frame descriptor - * @fd: the given frame descriptor - * @flc_addr: the flow context needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_flc(struct dpaa2_fd *fd, dma_addr_t flc_addr) -{ - fd->simple.flc = cpu_to_le64(flc_addr); -} - -static inline bool dpaa2_fd_short_len(const struct dpaa2_fd *fd) -{ - return !!((le16_to_cpu(fd->simple.format_offset) >> - FD_SHORT_LEN_FLAG_SHIFT) & FD_SHORT_LEN_FLAG_MASK); -} - -/** - * dpaa2_fd_get_len() - Get the length in the frame descriptor - * @fd: the given frame descriptor - * - * Return the length field in the frame descriptor. - */ -static inline u32 dpaa2_fd_get_len(const struct dpaa2_fd *fd) -{ - if (dpaa2_fd_short_len(fd)) - return le32_to_cpu(fd->simple.len) & FD_SHORT_LEN_MASK; - - return le32_to_cpu(fd->simple.len); -} - -/** - * dpaa2_fd_set_len() - Set the length field of frame descriptor - * @fd: the given frame descriptor - * @len: the length needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_len(struct dpaa2_fd *fd, u32 len) -{ - fd->simple.len = cpu_to_le32(len); -} - -/** - * dpaa2_fd_get_offset() - Get the offset field in the frame descriptor - * @fd: the given frame descriptor - * - * Return the offset. - */ -static inline uint16_t dpaa2_fd_get_offset(const struct dpaa2_fd *fd) -{ - return le16_to_cpu(fd->simple.format_offset) & FD_OFFSET_MASK; -} - -/** - * dpaa2_fd_set_offset() - Set the offset field of frame descriptor - * @fd: the given frame descriptor - * @offset: the offset needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_offset(struct dpaa2_fd *fd, uint16_t offset) -{ - fd->simple.format_offset &= cpu_to_le16(~FD_OFFSET_MASK); - fd->simple.format_offset |= cpu_to_le16(offset); -} - -/** - * dpaa2_fd_get_format() - Get the format field in the frame descriptor - * @fd: the given frame descriptor - * - * Return the format. - */ -static inline enum dpaa2_fd_format dpaa2_fd_get_format( - const struct dpaa2_fd *fd) -{ - return (enum dpaa2_fd_format)((le16_to_cpu(fd->simple.format_offset) - >> FD_FORMAT_SHIFT) & FD_FORMAT_MASK); -} - -/** - * dpaa2_fd_set_format() - Set the format field of frame descriptor - * @fd: the given frame descriptor - * @format: the format needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_format(struct dpaa2_fd *fd, - enum dpaa2_fd_format format) -{ - fd->simple.format_offset &= - cpu_to_le16(~(FD_FORMAT_MASK << FD_FORMAT_SHIFT)); - fd->simple.format_offset |= cpu_to_le16(format << FD_FORMAT_SHIFT); -} - -/** - * dpaa2_fd_get_bpid() - Get the bpid field in the frame descriptor - * @fd: the given frame descriptor - * - * Return the buffer pool id. - */ -static inline uint16_t dpaa2_fd_get_bpid(const struct dpaa2_fd *fd) -{ - return le16_to_cpu(fd->simple.bpid) & FD_BPID_MASK; -} - -/** - * dpaa2_fd_set_bpid() - Set the bpid field of frame descriptor - * @fd: the given frame descriptor - * @bpid: buffer pool id to be set - */ -static inline void dpaa2_fd_set_bpid(struct dpaa2_fd *fd, uint16_t bpid) -{ - fd->simple.bpid &= cpu_to_le16(~(FD_BPID_MASK)); - fd->simple.bpid |= cpu_to_le16(bpid); -} - -/** - * struct dpaa2_sg_entry - the scatter-gathering structure - * @addr: address of the sg entry - * @len: length in this sg entry - * @bpid: buffer pool id - * @format_offset: format and offset fields - */ -struct dpaa2_sg_entry { - __le64 addr; - __le32 len; - __le16 bpid; - __le16 format_offset; -}; - -enum dpaa2_sg_format { - dpaa2_sg_single = 0, - dpaa2_sg_frame_data, - dpaa2_sg_sgt_ext -}; - -/* Accessors for SG entry fields */ - -/** - * dpaa2_sg_get_addr() - Get the address from SG entry - * @sg: the given scatter-gathering object - * - * Return the address. - */ -static inline dma_addr_t dpaa2_sg_get_addr(const struct dpaa2_sg_entry *sg) -{ - return (dma_addr_t)le64_to_cpu(sg->addr); -} - -/** - * dpaa2_sg_set_addr() - Set the address in SG entry - * @sg: the given scatter-gathering object - * @addr: the address to be set - */ -static inline void dpaa2_sg_set_addr(struct dpaa2_sg_entry *sg, dma_addr_t addr) -{ - sg->addr = cpu_to_le64(addr); -} - -static inline bool dpaa2_sg_short_len(const struct dpaa2_sg_entry *sg) -{ - return !!((le16_to_cpu(sg->format_offset) >> SG_SHORT_LEN_FLAG_SHIFT) - & SG_SHORT_LEN_FLAG_MASK); -} - -/** - * dpaa2_sg_get_len() - Get the length in SG entry - * @sg: the given scatter-gathering object - * - * Return the length. - */ -static inline u32 dpaa2_sg_get_len(const struct dpaa2_sg_entry *sg) -{ - if (dpaa2_sg_short_len(sg)) - return le32_to_cpu(sg->len) & SG_SHORT_LEN_MASK; - - return le32_to_cpu(sg->len); -} - -/** - * dpaa2_sg_set_len() - Set the length in SG entry - * @sg: the given scatter-gathering object - * @len: the length to be set - */ -static inline void dpaa2_sg_set_len(struct dpaa2_sg_entry *sg, u32 len) -{ - sg->len = cpu_to_le32(len); -} - -/** - * dpaa2_sg_get_offset() - Get the offset in SG entry - * @sg: the given scatter-gathering object - * - * Return the offset. - */ -static inline u16 dpaa2_sg_get_offset(const struct dpaa2_sg_entry *sg) -{ - return le16_to_cpu(sg->format_offset) & SG_OFFSET_MASK; -} - -/** - * dpaa2_sg_set_offset() - Set the offset in SG entry - * @sg: the given scatter-gathering object - * @offset: the offset to be set - */ -static inline void dpaa2_sg_set_offset(struct dpaa2_sg_entry *sg, - u16 offset) -{ - sg->format_offset &= cpu_to_le16(~SG_OFFSET_MASK); - sg->format_offset |= cpu_to_le16(offset); -} - -/** - * dpaa2_sg_get_format() - Get the SG format in SG entry - * @sg: the given scatter-gathering object - * - * Return the format. - */ -static inline enum dpaa2_sg_format - dpaa2_sg_get_format(const struct dpaa2_sg_entry *sg) -{ - return (enum dpaa2_sg_format)((le16_to_cpu(sg->format_offset) - >> SG_FORMAT_SHIFT) & SG_FORMAT_MASK); -} - -/** - * dpaa2_sg_set_format() - Set the SG format in SG entry - * @sg: the given scatter-gathering object - * @format: the format to be set - */ -static inline void dpaa2_sg_set_format(struct dpaa2_sg_entry *sg, - enum dpaa2_sg_format format) -{ - sg->format_offset &= cpu_to_le16(~(SG_FORMAT_MASK << SG_FORMAT_SHIFT)); - sg->format_offset |= cpu_to_le16(format << SG_FORMAT_SHIFT); -} - -/** - * dpaa2_sg_get_bpid() - Get the buffer pool id in SG entry - * @sg: the given scatter-gathering object - * - * Return the bpid. - */ -static inline u16 dpaa2_sg_get_bpid(const struct dpaa2_sg_entry *sg) -{ - return le16_to_cpu(sg->bpid) & SG_BPID_MASK; -} - -/** - * dpaa2_sg_set_bpid() - Set the buffer pool id in SG entry - * @sg: the given scatter-gathering object - * @bpid: the bpid to be set - */ -static inline void dpaa2_sg_set_bpid(struct dpaa2_sg_entry *sg, u16 bpid) -{ - sg->bpid &= cpu_to_le16(~(SG_BPID_MASK)); - sg->bpid |= cpu_to_le16(bpid); -} - -/** - * dpaa2_sg_is_final() - Check final bit in SG entry - * @sg: the given scatter-gathering object - * - * Return bool. - */ -static inline bool dpaa2_sg_is_final(const struct dpaa2_sg_entry *sg) -{ - return !!(le16_to_cpu(sg->format_offset) >> SG_FINAL_FLAG_SHIFT); -} - -/** - * dpaa2_sg_set_final() - Set the final bit in SG entry - * @sg: the given scatter-gathering object - * @final: the final boolean to be set - */ -static inline void dpaa2_sg_set_final(struct dpaa2_sg_entry *sg, bool final) -{ - sg->format_offset &= cpu_to_le16((~(SG_FINAL_FLAG_MASK - << SG_FINAL_FLAG_SHIFT)) & 0xFFFF); - sg->format_offset |= cpu_to_le16(final << SG_FINAL_FLAG_SHIFT); -} - -#endif /* __FSL_DPAA2_FD_H */ diff --git a/drivers/staging/fsl-mc/include/dpaa2-global.h b/drivers/staging/fsl-mc/include/dpaa2-global.h deleted file mode 100644 index 9bc0713346a8..000000000000 --- a/drivers/staging/fsl-mc/include/dpaa2-global.h +++ /dev/null @@ -1,177 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016 NXP - * - */ -#ifndef __FSL_DPAA2_GLOBAL_H -#define __FSL_DPAA2_GLOBAL_H - -#include <linux/types.h> -#include <linux/cpumask.h> -#include "dpaa2-fd.h" - -struct dpaa2_dq { - union { - struct common { - u8 verb; - u8 reserved[63]; - } common; - struct dq { - u8 verb; - u8 stat; - __le16 seqnum; - __le16 oprid; - u8 reserved; - u8 tok; - __le32 fqid; - u32 reserved2; - __le32 fq_byte_cnt; - __le32 fq_frm_cnt; - __le64 fqd_ctx; - u8 fd[32]; - } dq; - struct scn { - u8 verb; - u8 stat; - u8 state; - u8 reserved; - __le32 rid_tok; - __le64 ctx; - } scn; - }; -}; - -/* Parsing frame dequeue results */ -/* FQ empty */ -#define DPAA2_DQ_STAT_FQEMPTY 0x80 -/* FQ held active */ -#define DPAA2_DQ_STAT_HELDACTIVE 0x40 -/* FQ force eligible */ -#define DPAA2_DQ_STAT_FORCEELIGIBLE 0x20 -/* valid frame */ -#define DPAA2_DQ_STAT_VALIDFRAME 0x10 -/* FQ ODP enable */ -#define DPAA2_DQ_STAT_ODPVALID 0x04 -/* volatile dequeue */ -#define DPAA2_DQ_STAT_VOLATILE 0x02 -/* volatile dequeue command is expired */ -#define DPAA2_DQ_STAT_EXPIRED 0x01 - -#define DQ_FQID_MASK 0x00FFFFFF -#define DQ_FRAME_COUNT_MASK 0x00FFFFFF - -/** - * dpaa2_dq_flags() - Get the stat field of dequeue response - * @dq: the dequeue result. - */ -static inline u32 dpaa2_dq_flags(const struct dpaa2_dq *dq) -{ - return dq->dq.stat; -} - -/** - * dpaa2_dq_is_pull() - Check whether the dq response is from a pull - * command. - * @dq: the dequeue result - * - * Return 1 for volatile(pull) dequeue, 0 for static dequeue. - */ -static inline int dpaa2_dq_is_pull(const struct dpaa2_dq *dq) -{ - return (int)(dpaa2_dq_flags(dq) & DPAA2_DQ_STAT_VOLATILE); -} - -/** - * dpaa2_dq_is_pull_complete() - Check whether the pull command is completed. - * @dq: the dequeue result - * - * Return boolean. - */ -static inline bool dpaa2_dq_is_pull_complete(const struct dpaa2_dq *dq) -{ - return !!(dpaa2_dq_flags(dq) & DPAA2_DQ_STAT_EXPIRED); -} - -/** - * dpaa2_dq_seqnum() - Get the seqnum field in dequeue response - * @dq: the dequeue result - * - * seqnum is valid only if VALIDFRAME flag is TRUE - * - * Return seqnum. - */ -static inline u16 dpaa2_dq_seqnum(const struct dpaa2_dq *dq) -{ - return le16_to_cpu(dq->dq.seqnum); -} - -/** - * dpaa2_dq_odpid() - Get the odpid field in dequeue response - * @dq: the dequeue result - * - * odpid is valid only if ODPVALID flag is TRUE. - * - * Return odpid. - */ -static inline u16 dpaa2_dq_odpid(const struct dpaa2_dq *dq) -{ - return le16_to_cpu(dq->dq.oprid); -} - -/** - * dpaa2_dq_fqid() - Get the fqid in dequeue response - * @dq: the dequeue result - * - * Return fqid. - */ -static inline u32 dpaa2_dq_fqid(const struct dpaa2_dq *dq) -{ - return le32_to_cpu(dq->dq.fqid) & DQ_FQID_MASK; -} - -/** - * dpaa2_dq_byte_count() - Get the byte count in dequeue response - * @dq: the dequeue result - * - * Return the byte count remaining in the FQ. - */ -static inline u32 dpaa2_dq_byte_count(const struct dpaa2_dq *dq) -{ - return le32_to_cpu(dq->dq.fq_byte_cnt); -} - -/** - * dpaa2_dq_frame_count() - Get the frame count in dequeue response - * @dq: the dequeue result - * - * Return the frame count remaining in the FQ. - */ -static inline u32 dpaa2_dq_frame_count(const struct dpaa2_dq *dq) -{ - return le32_to_cpu(dq->dq.fq_frm_cnt) & DQ_FRAME_COUNT_MASK; -} - -/** - * dpaa2_dq_fd_ctx() - Get the frame queue context in dequeue response - * @dq: the dequeue result - * - * Return the frame queue context. - */ -static inline u64 dpaa2_dq_fqd_ctx(const struct dpaa2_dq *dq) -{ - return le64_to_cpu(dq->dq.fqd_ctx); -} - -/** - * dpaa2_dq_fd() - Get the frame descriptor in dequeue response - * @dq: the dequeue result - * - * Return the frame descriptor. - */ -static inline const struct dpaa2_fd *dpaa2_dq_fd(const struct dpaa2_dq *dq) -{ - return (const struct dpaa2_fd *)&dq->dq.fd[0]; -} - -#endif /* __FSL_DPAA2_GLOBAL_H */ diff --git a/drivers/staging/fsl-mc/include/dpaa2-io.h b/drivers/staging/fsl-mc/include/dpaa2-io.h deleted file mode 100644 index ab51e40d11db..000000000000 --- a/drivers/staging/fsl-mc/include/dpaa2-io.h +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright NXP - * - */ -#ifndef __FSL_DPAA2_IO_H -#define __FSL_DPAA2_IO_H - -#include <linux/types.h> -#include <linux/cpumask.h> -#include <linux/irqreturn.h> - -#include "dpaa2-fd.h" -#include "dpaa2-global.h" - -struct dpaa2_io; -struct dpaa2_io_store; -struct device; - -/** - * DOC: DPIO Service - * - * The DPIO service provides APIs for users to interact with the datapath - * by enqueueing and dequeing frame descriptors. - * - * The following set of APIs can be used to enqueue and dequeue frames - * as well as producing notification callbacks when data is available - * for dequeue. - */ - -#define DPAA2_IO_ANY_CPU -1 - -/** - * struct dpaa2_io_desc - The DPIO descriptor - * @receives_notifications: Use notificaton mode. Non-zero if the DPIO - * has a channel. - * @has_8prio: Set to non-zero for channel with 8 priority WQs. Ignored - * unless receives_notification is TRUE. - * @cpu: The cpu index that at least interrupt handlers will - * execute on. - * @stash_affinity: The stash affinity for this portal favour 'cpu' - * @regs_cena: The cache enabled regs. - * @regs_cinh: The cache inhibited regs - * @dpio_id: The dpio index - * @qman_version: The qman version - * - * Describes the attributes and features of the DPIO object. - */ -struct dpaa2_io_desc { - int receives_notifications; - int has_8prio; - int cpu; - void *regs_cena; - void __iomem *regs_cinh; - int dpio_id; - u32 qman_version; -}; - -struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc); - -void dpaa2_io_down(struct dpaa2_io *d); - -irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj); - -struct dpaa2_io *dpaa2_io_service_select(int cpu); - -/** - * struct dpaa2_io_notification_ctx - The DPIO notification context structure - * @cb: The callback to be invoked when the notification arrives - * @is_cdan: Zero for FQDAN, non-zero for CDAN - * @id: FQID or channel ID, needed for rearm - * @desired_cpu: The cpu on which the notifications will show up. Use - * DPAA2_IO_ANY_CPU if don't care - * @dpio_id: The dpio index - * @qman64: The 64-bit context value shows up in the FQDAN/CDAN. - * @node: The list node - * @dpio_private: The dpio object internal to dpio_service - * - * Used when a FQDAN/CDAN registration is made by drivers. - */ -struct dpaa2_io_notification_ctx { - void (*cb)(struct dpaa2_io_notification_ctx *ctx); - int is_cdan; - u32 id; - int desired_cpu; - int dpio_id; - u64 qman64; - struct list_head node; - void *dpio_private; -}; - -int dpaa2_io_service_register(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); -void dpaa2_io_service_deregister(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); -int dpaa2_io_service_rearm(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); - -int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid, - struct dpaa2_io_store *s); - -int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio, - u16 qdbin, const struct dpaa2_fd *fd); -int dpaa2_io_service_release(struct dpaa2_io *d, u32 bpid, - const u64 *buffers, unsigned int num_buffers); -int dpaa2_io_service_acquire(struct dpaa2_io *d, u32 bpid, - u64 *buffers, unsigned int num_buffers); - -struct dpaa2_io_store *dpaa2_io_store_create(unsigned int max_frames, - struct device *dev); -void dpaa2_io_store_destroy(struct dpaa2_io_store *s); -struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last); - -#endif /* __FSL_DPAA2_IO_H */ diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 8e223799347a..94bad43c41ff 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -57,9 +57,8 @@ static DEFINE_SPINLOCK(tiqn_lock); static DEFINE_MUTEX(np_lock); static struct idr tiqn_idr; -struct idr sess_idr; +DEFINE_IDA(sess_ida); struct mutex auth_id_lock; -spinlock_t sess_idr_lock; struct iscsit_global *iscsit_global; @@ -700,9 +699,7 @@ static int __init iscsi_target_init_module(void) spin_lock_init(&iscsit_global->ts_bitmap_lock); mutex_init(&auth_id_lock); - spin_lock_init(&sess_idr_lock); idr_init(&tiqn_idr); - idr_init(&sess_idr); ret = target_register_template(&iscsi_ops); if (ret) @@ -4375,10 +4372,7 @@ int iscsit_close_session(struct iscsi_session *sess) pr_debug("Decremented number of active iSCSI Sessions on" " iSCSI TPG: %hu to %u\n", tpg->tpgt, tpg->nsessions); - spin_lock(&sess_idr_lock); - idr_remove(&sess_idr, sess->session_index); - spin_unlock(&sess_idr_lock); - + ida_free(&sess_ida, sess->session_index); kfree(sess->sess_ops); sess->sess_ops = NULL; spin_unlock_bh(&se_tpg->session_lock); diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index 42de1843aa40..48bac0acf8c7 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -55,9 +55,7 @@ extern struct kmem_cache *lio_ooo_cache; extern struct kmem_cache *lio_qr_cache; extern struct kmem_cache *lio_r2t_cache; -extern struct idr sess_idr; +extern struct ida sess_ida; extern struct mutex auth_id_lock; -extern spinlock_t sess_idr_lock; - #endif /*** ISCSI_TARGET_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 923b1a9fc3dc..9e74f8bc2963 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -336,22 +336,15 @@ static int iscsi_login_zero_tsih_s1( timer_setup(&sess->time2retain_timer, iscsit_handle_time2retain_timeout, 0); - idr_preload(GFP_KERNEL); - spin_lock_bh(&sess_idr_lock); - ret = idr_alloc(&sess_idr, NULL, 0, 0, GFP_NOWAIT); - if (ret >= 0) - sess->session_index = ret; - spin_unlock_bh(&sess_idr_lock); - idr_preload_end(); - + ret = ida_alloc(&sess_ida, GFP_KERNEL); if (ret < 0) { - pr_err("idr_alloc() for sess_idr failed\n"); + pr_err("Session ID allocation failed %d\n", ret); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); - kfree(sess); - return -ENOMEM; + goto free_sess; } + sess->session_index = ret; sess->creation_time = get_jiffies_64(); /* * The FFP CmdSN window values will be allocated from the TPG's @@ -365,20 +358,26 @@ static int iscsi_login_zero_tsih_s1( ISCSI_LOGIN_STATUS_NO_RESOURCES); pr_err("Unable to allocate memory for" " struct iscsi_sess_ops.\n"); - kfree(sess); - return -ENOMEM; + goto free_id; } sess->se_sess = transport_alloc_session(TARGET_PROT_NORMAL); if (IS_ERR(sess->se_sess)) { iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); - kfree(sess->sess_ops); - kfree(sess); - return -ENOMEM; + goto free_ops; } return 0; + +free_ops: + kfree(sess->sess_ops); +free_id: + ida_free(&sess_ida, sess->session_index); +free_sess: + kfree(sess); + conn->sess = NULL; + return -ENOMEM; } static int iscsi_login_zero_tsih_s2( @@ -1161,13 +1160,9 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn, ISCSI_LOGIN_STATUS_INIT_ERR); if (!zero_tsih || !conn->sess) goto old_sess_out; - if (conn->sess->se_sess) - transport_free_session(conn->sess->se_sess); - if (conn->sess->session_index != 0) { - spin_lock_bh(&sess_idr_lock); - idr_remove(&sess_idr, conn->sess->session_index); - spin_unlock_bh(&sess_idr_lock); - } + + transport_free_session(conn->sess->se_sess); + ida_free(&sess_ida, conn->sess->session_index); kfree(conn->sess->sess_ops); kfree(conn->sess); conn->sess = NULL; diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index 0126de898036..3c59e19029be 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -5,3 +5,11 @@ config OPTEE help This implements the OP-TEE Trusted Execution Environment (TEE) driver. + +config OPTEE_SHM_NUM_PRIV_PAGES + int "Private Shared Memory Pages" + default 1 + depends on OPTEE + help + This sets the number of private shared memory pages to be + used by OP-TEE TEE driver. diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index e5fd5ed217da..e1aafe842d66 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -32,7 +32,7 @@ #define DRIVER_NAME "optee" -#define OPTEE_SHM_NUM_PRIV_PAGES 1 +#define OPTEE_SHM_NUM_PRIV_PAGES CONFIG_OPTEE_SHM_NUM_PRIV_PAGES /** * optee_from_msg_param() - convert from OPTEE_MSG parameters to diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c index 41aea12e2bcc..b45c73dd37a5 100644 --- a/drivers/tee/optee/rpc.c +++ b/drivers/tee/optee/rpc.c @@ -48,7 +48,7 @@ static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg) OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT) goto bad; - getnstimeofday64(&ts); + ktime_get_real_ts64(&ts); arg->params[0].u.value.a = ts.tv_sec; arg->params[0].u.value.b = ts.tv_nsec; diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 82979880f985..0e69edc77d18 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -360,7 +360,7 @@ config INTEL_SOC_DTS_IOSF_CORE config INTEL_SOC_DTS_THERMAL tristate "Intel SoCs DTS thermal driver" - depends on X86 && PCI + depends on X86 && PCI && ACPI select INTEL_SOC_DTS_IOSF_CORE select THERMAL_WRITABLE_TRIPS help diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 4540e892b61d..cde891c54cde 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -28,7 +28,7 @@ * case of external interrupts without need for ack, clamping down * cpu in non-irq context does not reduce irq. for majority of the * cases, clamping down cpu does help reduce irq as well, we should - * be able to differenciate the two cases and give a quantitative + * be able to differentiate the two cases and give a quantitative * solution for the irqs that we can control. perhaps based on * get_cpu_iowait_time_us() * diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index c27868b2c6af..1e47511a6bd5 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c @@ -15,6 +15,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/acpi.h> #include <linux/module.h> #include <linux/interrupt.h> #include <asm/cpu_device_id.h> @@ -31,6 +32,7 @@ MODULE_PARM_DESC(crit_offset, /* IRQ 86 is a fixed APIC interrupt for BYT DTS Aux threshold notifications */ #define BYT_SOC_DTS_APIC_IRQ 86 +static int soc_dts_thres_gsi; static int soc_dts_thres_irq; static struct intel_soc_dts_sensors *soc_dts; @@ -65,7 +67,21 @@ static int __init intel_soc_thermal_init(void) return err; } - soc_dts_thres_irq = (int)match_cpu->driver_data; + soc_dts_thres_gsi = (int)match_cpu->driver_data; + if (soc_dts_thres_gsi) { + /* + * Note the flags here MUST match the firmware defaults, rather + * then the request_irq flags, otherwise we get an EBUSY error. + */ + soc_dts_thres_irq = acpi_register_gsi(NULL, soc_dts_thres_gsi, + ACPI_LEVEL_SENSITIVE, + ACPI_ACTIVE_LOW); + if (soc_dts_thres_irq < 0) { + pr_warn("intel_soc_dts: Could not get IRQ for GSI %d, err %d\n", + soc_dts_thres_gsi, soc_dts_thres_irq); + soc_dts_thres_irq = 0; + } + } if (soc_dts_thres_irq) { err = request_threaded_irq(soc_dts_thres_irq, NULL, @@ -90,8 +106,10 @@ static int __init intel_soc_thermal_init(void) return 0; error_trips: - if (soc_dts_thres_irq) + if (soc_dts_thres_irq) { free_irq(soc_dts_thres_irq, soc_dts); + acpi_unregister_gsi(soc_dts_thres_gsi); + } intel_soc_dts_iosf_exit(soc_dts); return err; @@ -99,8 +117,10 @@ error_trips: static void __exit intel_soc_thermal_exit(void) { - if (soc_dts_thres_irq) + if (soc_dts_thres_irq) { free_irq(soc_dts_thres_irq, soc_dts); + acpi_unregister_gsi(soc_dts_thres_gsi); + } intel_soc_dts_iosf_exit(soc_dts); } diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index f631f8bee308..77baf895108f 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -52,6 +52,7 @@ static u32 hvc_opal_boot_termno; static const struct hv_ops hvc_opal_raw_ops = { .get_chars = opal_get_chars, .put_chars = opal_put_chars, + .flush = opal_flush_chars, .notifier_add = notifier_add_irq, .notifier_del = notifier_del_irq, .notifier_hangup = notifier_hangup_irq, @@ -141,6 +142,7 @@ static int hvc_opal_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set, static const struct hv_ops hvc_opal_hvsi_ops = { .get_chars = hvc_opal_hvsi_get_chars, .put_chars = hvc_opal_hvsi_put_chars, + .flush = opal_flush_chars, .notifier_add = hvc_opal_hvsi_open, .notifier_del = hvc_opal_hvsi_close, .notifier_hangup = hvc_opal_hvsi_hangup, diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 6364890575ec..06ed20dd01ba 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -348,7 +348,7 @@ static void send_sig_all(int sig) if (is_global_init(p)) continue; - do_send_sig_info(sig, SEND_SIG_FORCED, p, true); + do_send_sig_info(sig, SEND_SIG_FORCED, p, PIDTYPE_MAX); } read_unlock(&tasklist_lock); } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 11c2df904ac9..32bc3e3fe4d3 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2113,7 +2113,7 @@ static int __tty_fasync(int fd, struct file *filp, int on) type = PIDTYPE_PGID; } else { pid = task_pid(current); - type = PIDTYPE_PID; + type = PIDTYPE_TGID; } get_pid(pid); spin_unlock_irqrestore(&tty->ctrl_lock, flags); diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index d9145a8f35d2..8e3bab1e0c1f 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -161,16 +161,10 @@ static int exynos_ehci_probe(struct platform_device *pdev) } exynos_ehci = to_exynos_ehci(hcd); - if (of_device_is_compatible(pdev->dev.of_node, - "samsung,exynos5440-ehci")) - goto skip_phy; - err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci); if (err) goto fail_clk; -skip_phy: - exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ehci->clk)) { @@ -304,7 +298,6 @@ static const struct dev_pm_ops exynos_ehci_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id exynos_ehci_match[] = { { .compatible = "samsung,exynos4210-ehci" }, - { .compatible = "samsung,exynos5440-ehci" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_ehci_match); diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index a39fae41bc70..c0c4dcca6f3c 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -130,15 +130,10 @@ static int exynos_ohci_probe(struct platform_device *pdev) exynos_ohci = to_exynos_ohci(hcd); - if (of_device_is_compatible(pdev->dev.of_node, - "samsung,exynos5440-ohci")) - goto skip_phy; - err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci); if (err) goto fail_clk; -skip_phy: exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ohci->clk)) { @@ -270,7 +265,6 @@ static const struct dev_pm_ops exynos_ohci_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id exynos_ohci_match[] = { { .compatible = "samsung,exynos4210-ohci" }, - { .compatible = "samsung,exynos5440-ohci" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_ohci_match); diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index cfdecea5078f..b580885243f7 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -12,7 +12,7 @@ config VHOST_NET config VHOST_SCSI tristate "VHOST_SCSI TCM fabric driver" - depends on TARGET_CORE && EVENTFD && m + depends on TARGET_CORE && EVENTFD select VHOST default n ---help--- diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 76f8d649147b..c24bb690680b 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -55,7 +55,7 @@ #define VHOST_SCSI_DEFAULT_TAGS 256 #define VHOST_SCSI_PREALLOC_SGLS 2048 #define VHOST_SCSI_PREALLOC_UPAGES 2048 -#define VHOST_SCSI_PREALLOC_PROT_SGLS 512 +#define VHOST_SCSI_PREALLOC_PROT_SGLS 2048 struct vhost_scsi_inflight { /* Wait for the flush operation to finish */ diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 96c1d8400822..b13c6b4b2c66 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -952,7 +952,7 @@ static void vhost_iotlb_notify_vq(struct vhost_dev *d, list_for_each_entry_safe(node, n, &d->pending_list, node) { struct vhost_iotlb_msg *vq_msg = &node->msg.iotlb; if (msg->iova <= vq_msg->iova && - msg->iova + msg->size - 1 > vq_msg->iova && + msg->iova + msg->size - 1 >= vq_msg->iova && vq_msg->type == VHOST_IOTLB_MISS) { vhost_poll_queue(&node->vq->poll); list_del(&node->node); diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 16119bde9750..f1dc41cf19e3 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -690,6 +690,7 @@ static int adp8860_probe(struct i2c_client *client, switch (ADP8860_MANID(reg_val)) { case ADP8863_MANUFID: data->gdwn_dis = !!pdata->gdwn_dis; + /* fall through */ case ADP8860_MANUFID: data->en_ambl_sens = !!pdata->en_ambl_sens; break; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 44ac5bde4e9d..bdfcc0a71db1 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -143,11 +143,116 @@ static const struct backlight_ops pwm_backlight_ops = { }; #ifdef CONFIG_OF +#define PWM_LUMINANCE_SCALE 10000 /* luminance scale */ + +/* An integer based power function */ +static u64 int_pow(u64 base, int exp) +{ + u64 result = 1; + + while (exp) { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; +} + +/* + * CIE lightness to PWM conversion. + * + * The CIE 1931 lightness formula is what actually describes how we perceive + * light: + * Y = (L* / 902.3) if L* ≤ 0.08856 + * Y = ((L* + 16) / 116)^3 if L* > 0.08856 + * + * Where Y is the luminance, the amount of light coming out of the screen, and + * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human + * perceives the screen to be, and is a number between 0 and 100. + * + * The following function does the fixed point maths needed to implement the + * above formula. + */ +static u64 cie1931(unsigned int lightness, unsigned int scale) +{ + u64 retval; + + lightness *= 100; + if (lightness <= (8 * scale)) { + retval = DIV_ROUND_CLOSEST_ULL(lightness * 10, 9023); + } else { + retval = int_pow((lightness + (16 * scale)) / 116, 3); + retval = DIV_ROUND_CLOSEST_ULL(retval, (scale * scale)); + } + + return retval; +} + +/* + * Create a default correction table for PWM values to create linear brightness + * for LED based backlights using the CIE1931 algorithm. + */ +static +int pwm_backlight_brightness_default(struct device *dev, + struct platform_pwm_backlight_data *data, + unsigned int period) +{ + unsigned int counter = 0; + unsigned int i, n; + u64 retval; + + /* + * Count the number of bits needed to represent the period number. The + * number of bits is used to calculate the number of levels used for the + * brightness-levels table, the purpose of this calculation is have a + * pre-computed table with enough levels to get linear brightness + * perception. The period is divided by the number of bits so for a + * 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM + * we have 65535 / 16 = 4096 brightness levels. + * + * Note that this method is based on empirical testing on different + * devices with PWM of 8 and 16 bits of resolution. + */ + n = period; + while (n) { + counter += n % 2; + n >>= 1; + } + + data->max_brightness = DIV_ROUND_UP(period, counter); + data->levels = devm_kcalloc(dev, data->max_brightness, + sizeof(*data->levels), GFP_KERNEL); + if (!data->levels) + return -ENOMEM; + + /* Fill the table using the cie1931 algorithm */ + for (i = 0; i < data->max_brightness; i++) { + retval = cie1931((i * PWM_LUMINANCE_SCALE) / + data->max_brightness, PWM_LUMINANCE_SCALE) * + period; + retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE); + if (retval > UINT_MAX) + return -EINVAL; + data->levels[i] = (unsigned int)retval; + } + + data->dft_brightness = data->max_brightness / 2; + data->max_brightness--; + + return 0; +} + static int pwm_backlight_parse_dt(struct device *dev, struct platform_pwm_backlight_data *data) { struct device_node *node = dev->of_node; + unsigned int num_levels = 0; + unsigned int levels_count; + unsigned int num_steps = 0; struct property *prop; + unsigned int *table; int length; u32 value; int ret; @@ -157,16 +262,20 @@ static int pwm_backlight_parse_dt(struct device *dev, memset(data, 0, sizeof(*data)); - /* determine the number of brightness levels */ + /* + * Determine the number of brightness levels, if this property is not + * set a default table of brightness levels will be used. + */ prop = of_find_property(node, "brightness-levels", &length); if (!prop) - return -EINVAL; + return 0; data->max_brightness = length / sizeof(u32); /* read brightness levels from DT property */ if (data->max_brightness > 0) { size_t size = sizeof(*data->levels) * data->max_brightness; + unsigned int i, j, n = 0; data->levels = devm_kzalloc(dev, size, GFP_KERNEL); if (!data->levels) @@ -184,6 +293,84 @@ static int pwm_backlight_parse_dt(struct device *dev, return ret; data->dft_brightness = value; + + /* + * This property is optional, if is set enables linear + * interpolation between each of the values of brightness levels + * and creates a new pre-computed table. + */ + of_property_read_u32(node, "num-interpolated-steps", + &num_steps); + + /* + * Make sure that there is at least two entries in the + * brightness-levels table, otherwise we can't interpolate + * between two points. + */ + if (num_steps) { + if (data->max_brightness < 2) { + dev_err(dev, "can't interpolate\n"); + return -EINVAL; + } + + /* + * Recalculate the number of brightness levels, now + * taking in consideration the number of interpolated + * steps between two levels. + */ + for (i = 0; i < data->max_brightness - 1; i++) { + if ((data->levels[i + 1] - data->levels[i]) / + num_steps) + num_levels += num_steps; + else + num_levels++; + } + num_levels++; + dev_dbg(dev, "new number of brightness levels: %d\n", + num_levels); + + /* + * Create a new table of brightness levels with all the + * interpolated steps. + */ + size = sizeof(*table) * num_levels; + table = devm_kzalloc(dev, size, GFP_KERNEL); + if (!table) + return -ENOMEM; + + /* Fill the interpolated table. */ + levels_count = 0; + for (i = 0; i < data->max_brightness - 1; i++) { + value = data->levels[i]; + n = (data->levels[i + 1] - value) / num_steps; + if (n > 0) { + for (j = 0; j < num_steps; j++) { + table[levels_count] = value; + value += n; + levels_count++; + } + } else { + table[levels_count] = data->levels[i]; + levels_count++; + } + } + table[levels_count] = data->levels[i]; + + /* + * As we use interpolation lets remove current + * brightness levels table and replace for the + * new interpolated table. + */ + devm_kfree(dev, data->levels); + data->levels = table; + + /* + * Reassign max_brightness value to the new total number + * of brightness levels. + */ + data->max_brightness = num_levels; + } + data->max_brightness--; } @@ -211,6 +398,14 @@ static int pwm_backlight_parse_dt(struct device *dev, { return -ENODEV; } + +static +int pwm_backlight_brightness_default(struct device *dev, + struct platform_pwm_backlight_data *data, + unsigned int period) +{ + return -ENODEV; +} #endif static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb) @@ -251,7 +446,9 @@ static int pwm_backlight_probe(struct platform_device *pdev) struct backlight_device *bl; struct device_node *node = pdev->dev.of_node; struct pwm_bl_data *pb; + struct pwm_state state; struct pwm_args pargs; + unsigned int i; int ret; if (!data) { @@ -276,17 +473,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) goto err_alloc; } - if (data->levels) { - unsigned int i; - - for (i = 0; i <= data->max_brightness; i++) - if (data->levels[i] > pb->scale) - pb->scale = data->levels[i]; - - pb->levels = data->levels; - } else - pb->scale = data->max_brightness; - pb->notify = data->notify; pb->notify_after = data->notify_after; pb->check_fb = data->check_fb; @@ -353,6 +539,26 @@ static int pwm_backlight_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "got pwm for backlight\n"); + if (!data->levels) { + /* Get the PWM period (in nanoseconds) */ + pwm_get_state(pb->pwm, &state); + + ret = pwm_backlight_brightness_default(&pdev->dev, data, + state.period); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to setup default brightness table\n"); + goto err_alloc; + } + } + + for (i = 0; i <= data->max_brightness; i++) { + if (data->levels[i] > pb->scale) + pb->scale = data->levels[i]; + + pb->levels = data->levels; + } + /* * FIXME: pwm_apply_args() should be removed when switching to * the atomic PWM API. diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index e91edef98633..787792c3d08d 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -152,7 +152,7 @@ config FRAMEBUFFER_CONSOLE_ROTATION config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER bool "Framebuffer Console Deferred Takeover" - depends on FRAMEBUFFER_CONSOLE=y && DUMMY_CONSOLE=y + depends on FB=y && FRAMEBUFFER_CONSOLE && DUMMY_CONSOLE help If enabled this defers the framebuffer console taking over the console from the dummy console until the first text is displayed on diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0254251fdd79..45ad925ad5f8 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -38,13 +38,11 @@ void dummycon_register_output_notifier(struct notifier_block *nb) if (dummycon_putc_called) nb->notifier_call(nb, 0, NULL); } -EXPORT_SYMBOL_GPL(dummycon_register_output_notifier); void dummycon_unregister_output_notifier(struct notifier_block *nb) { raw_notifier_chain_unregister(&dummycon_output_nh, nb); } -EXPORT_SYMBOL_GPL(dummycon_unregister_output_notifier); static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f09e17b60e45..09731b2f6815 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -112,6 +112,11 @@ EXPORT_SYMBOL(vgacon_text_force); static int __init text_mode(char *str) { vgacon_text_mode_force = true; + + pr_warning("You have booted with nomodeset. This means your GPU drivers are DISABLED\n"); + pr_warning("Any video related functionality will be severely degraded, and you may not even be able to suspend the system properly\n"); + pr_warning("Unless you actually understand what nomodeset does, you should reboot without enabling it\n"); + return 1; } diff --git a/drivers/video/fbdev/amifb.c b/drivers/video/fbdev/amifb.c index cc11c6061298..0777aff211e5 100644 --- a/drivers/video/fbdev/amifb.c +++ b/drivers/video/fbdev/amifb.c @@ -2303,7 +2303,7 @@ static void ami_build_copper(struct fb_info *info) ami_rebuild_copper(info->par); } - +#ifndef MODULE static void __init amifb_setup_mcap(char *spec) { char *p; @@ -2368,7 +2368,7 @@ static int __init amifb_setup(char *options) return 0; } - +#endif static int amifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 5fb156bdcf4e..75ebbbf0a1fb 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2234,8 +2234,8 @@ static int fbcon_switch(struct vc_data *vc) * * info->currcon = vc->vc_num; */ - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { + for_each_registered_fb(i) { + if (registered_fb[i]->fbcon_par) { struct fbcon_ops *o = registered_fb[i]->fbcon_par; o->currcon = vc->vc_num; @@ -3124,11 +3124,9 @@ static int fbcon_fb_unregistered(struct fb_info *info) if (idx == info_idx) { info_idx = -1; - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i] != NULL) { - info_idx = i; - break; - } + for_each_registered_fb(i) { + info_idx = i; + break; } } @@ -3594,13 +3592,24 @@ static int fbcon_init_device(void) } #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER +static void fbcon_register_existing_fbs(struct work_struct *work) +{ + int i; + + console_lock(); + + for_each_registered_fb(i) + fbcon_fb_registered(registered_fb[i]); + + console_unlock(); +} + static struct notifier_block fbcon_output_nb; +static DECLARE_WORK(fbcon_deferred_takeover_work, fbcon_register_existing_fbs); static int fbcon_output_notifier(struct notifier_block *nb, unsigned long action, void *data) { - int i; - WARN_CONSOLE_UNLOCKED(); pr_info("fbcon: Taking over console\n"); @@ -3609,45 +3618,37 @@ static int fbcon_output_notifier(struct notifier_block *nb, deferred_takeover = false; logo_shown = FBCON_LOGO_DONTSHOW; - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i]) - fbcon_fb_registered(registered_fb[i]); - } + /* We may get called in atomic context */ + schedule_work(&fbcon_deferred_takeover_work); return NOTIFY_OK; } - -static void fbcon_register_output_notifier(void) -{ - fbcon_output_nb.notifier_call = fbcon_output_notifier; - dummycon_register_output_notifier(&fbcon_output_nb); -} -#else -static inline void fbcon_register_output_notifier(void) {} #endif static void fbcon_start(void) { + WARN_CONSOLE_UNLOCKED(); + +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER + if (conswitchp != &dummy_con) + deferred_takeover = false; + if (deferred_takeover) { - fbcon_register_output_notifier(); + fbcon_output_nb.notifier_call = fbcon_output_notifier; + dummycon_register_output_notifier(&fbcon_output_nb); return; } +#endif if (num_registered_fb) { int i; - console_lock(); - - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i] != NULL) { - info_idx = i; - break; - } + for_each_registered_fb(i) { + info_idx = i; + break; } do_fbcon_takeover(0); - console_unlock(); - } } @@ -3669,15 +3670,12 @@ static void fbcon_exit(void) kfree((void *)softback_buf); softback_buf = 0UL; - for (i = 0; i < FB_MAX; i++) { + for_each_registered_fb(i) { int pending = 0; mapped = 0; info = registered_fb[i]; - if (info == NULL) - continue; - if (info->queue.func) pending = cancel_work_sync(&info->queue); DPRINTK("fbcon: %s pending work\n", (pending ? "canceled" : @@ -3733,8 +3731,8 @@ void __init fb_console_init(void) for (i = 0; i < MAX_NR_CONSOLES; i++) con2fb_map[i] = -1; - console_unlock(); fbcon_start(); + console_unlock(); } #ifdef MODULE diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 609438d2465b..20405421a5ed 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1347,6 +1347,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, case FBIOGET_CON2FBMAP: case FBIOPUT_CON2FBMAP: arg = (unsigned long) compat_ptr(arg); + /* fall through */ case FBIOBLANK: ret = do_fb_ioctl(info, cmd, arg); break; @@ -1593,10 +1594,8 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a, int i, ret; /* check all firmware fbs and kick off if the base addr overlaps */ - for (i = 0 ; i < FB_MAX; i++) { + for_each_registered_fb(i) { struct apertures_struct *gen_aper; - if (!registered_fb[i]) - continue; if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) continue; @@ -1691,25 +1690,30 @@ static int do_register_framebuffer(struct fb_info *fb_info) event.info = fb_info; if (!lockless_register_fb) console_lock(); + else + atomic_inc(&ignore_console_lock_warning); if (!lock_fb_info(fb_info)) { - if (!lockless_register_fb) - console_unlock(); - return -ENODEV; + ret = -ENODEV; + goto unlock_console; } + ret = 0; fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); unlock_fb_info(fb_info); +unlock_console: if (!lockless_register_fb) console_unlock(); - return 0; + else + atomic_dec(&ignore_console_lock_warning); + return ret; } -static int do_unregister_framebuffer(struct fb_info *fb_info) +static int unbind_console(struct fb_info *fb_info) { struct fb_event event; - int i, ret = 0; + int ret; + int i = fb_info->node; - i = fb_info->node; if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) return -EINVAL; @@ -1724,17 +1728,29 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) unlock_fb_info(fb_info); console_unlock(); + return ret; +} + +static int __unlink_framebuffer(struct fb_info *fb_info); + +static int do_unregister_framebuffer(struct fb_info *fb_info) +{ + struct fb_event event; + int ret; + + ret = unbind_console(fb_info); + if (ret) return -EINVAL; pm_vt_switch_unregister(fb_info->dev); - unlink_framebuffer(fb_info); + __unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); fb_destroy_modelist(&fb_info->modelist); - registered_fb[i] = NULL; + registered_fb[fb_info->node] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); event.info = fb_info; @@ -1747,7 +1763,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) return 0; } -int unlink_framebuffer(struct fb_info *fb_info) +static int __unlink_framebuffer(struct fb_info *fb_info) { int i; @@ -1759,6 +1775,20 @@ int unlink_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); fb_info->dev = NULL; } + + return 0; +} + +int unlink_framebuffer(struct fb_info *fb_info) +{ + int ret; + + ret = __unlink_framebuffer(fb_info); + if (ret) + return ret; + + unbind_console(fb_info); + return 0; } EXPORT_SYMBOL(unlink_framebuffer); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 2510fa728d77..283d9307df21 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -628,45 +628,47 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, } /** - * fb_find_mode - finds a valid video mode - * @var: frame buffer user defined part of display - * @info: frame buffer info structure - * @mode_option: string video mode to find - * @db: video mode database - * @dbsize: size of @db - * @default_mode: default video mode to fall back to - * @default_bpp: default color depth in bits per pixel + * fb_find_mode - finds a valid video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode_option: string video mode to find + * @db: video mode database + * @dbsize: size of @db + * @default_mode: default video mode to fall back to + * @default_bpp: default color depth in bits per pixel * - * Finds a suitable video mode, starting with the specified mode - * in @mode_option with fallback to @default_mode. If - * @default_mode fails, all modes in the video mode database will - * be tried. + * Finds a suitable video mode, starting with the specified mode + * in @mode_option with fallback to @default_mode. If + * @default_mode fails, all modes in the video mode database will + * be tried. * - * Valid mode specifiers for @mode_option: + * Valid mode specifiers for @mode_option:: * - * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or - * <name>[-<bpp>][@<refresh>] + * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m] + * + * or :: * - * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and - * <name> a string. + * <name>[-<bpp>][@<refresh>] * - * If 'M' is present after yres (and before refresh/bpp if present), - * the function will compute the timings using VESA(tm) Coordinated - * Video Timings (CVT). If 'R' is present after 'M', will compute with - * reduced blanking (for flatpanels). If 'i' is present, compute - * interlaced mode. If 'm' is present, add margins equal to 1.8% - * of xres rounded down to 8 pixels, and 1.8% of yres. The char - * 'i' and 'm' must be after 'M' and 'R'. Example: + * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and + * <name> a string. * - * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. + * If 'M' is present after yres (and before refresh/bpp if present), + * the function will compute the timings using VESA(tm) Coordinated + * Video Timings (CVT). If 'R' is present after 'M', will compute with + * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute + * interlaced or progressive mode. If 'm' is present, add margins equal + * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The char + * 'i', 'p' and 'm' must be after 'M' and 'R'. Example:: * - * NOTE: The passed struct @var is _not_ cleared! This allows you - * to supply values for e.g. the grayscale and accel_flags fields. + * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. * - * Returns zero for failure, 1 if using specified @mode_option, - * 2 if using specified @mode_option with an ignored refresh rate, - * 3 if default mode is used, 4 if fall back to any valid mode. + * NOTE: The passed struct @var is _not_ cleared! This allows you + * to supply values for e.g. the grayscale and accel_flags fields. * + * Returns zero for failure, 1 if using specified @mode_option, + * 2 if using specified @mode_option with an ignored refresh rate, + * 3 if default mode is used, 4 if fall back to any valid mode. */ int fb_find_mode(struct fb_var_screeninfo *var, @@ -697,7 +699,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0; + int yres_specified = 0, cvt = 0, rb = 0; + int interlace_specified = 0, interlace = 0; int margins = 0; u32 best, diff, tdiff; @@ -748,9 +751,17 @@ int fb_find_mode(struct fb_var_screeninfo *var, if (!cvt) margins = 1; break; + case 'p': + if (!cvt) { + interlace = 0; + interlace_specified = 1; + } + break; case 'i': - if (!cvt) + if (!cvt) { interlace = 1; + interlace_specified = 1; + } break; default: goto done; @@ -819,11 +830,21 @@ done: if ((name_matches(db[i], name, namelen) || (res_specified && res_matches(db[i], xres, yres))) && !fb_try_mode(var, info, &db[i], bpp)) { - if (refresh_specified && db[i].refresh == refresh) - return 1; + const int db_interlace = (db[i].vmode & + FB_VMODE_INTERLACED ? 1 : 0); + int score = abs(db[i].refresh - refresh); + + if (interlace_specified) + score += abs(db_interlace - interlace); + + if (!interlace_specified || + db_interlace == interlace) + if (refresh_specified && + db[i].refresh == refresh) + return 1; - if (abs(db[i].refresh - refresh) < diff) { - diff = abs(db[i].refresh - refresh); + if (score < diff) { + diff = score; best = i; } } diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index c6f78d27947b..3946649b85c8 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -9,16 +9,39 @@ #include <linux/kernel.h> #include <linux/efi.h> +#include <linux/efi-bgrt.h> #include <linux/errno.h> #include <linux/fb.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/printk.h> #include <linux/screen_info.h> #include <video/vga.h> #include <asm/efi.h> #include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */ #include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */ +struct bmp_file_header { + u16 id; + u32 file_size; + u32 reserved; + u32 bitmap_offset; +} __packed; + +struct bmp_dib_header { + u32 dib_header_size; + s32 width; + s32 height; + u16 planes; + u16 bpp; + u32 compression; + u32 bitmap_size; + u32 horz_resolution; + u32 vert_resolution; + u32 colors_used; + u32 colors_important; +} __packed; + static bool request_mem_succeeded = false; static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC; @@ -66,6 +89,164 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +/* + * If fbcon deffered console takeover is configured, the intent is for the + * framebuffer to show the boot graphics (e.g. vendor logo) until there is some + * (error) message to display. But the boot graphics may have been destroyed by + * e.g. option ROM output, detect this and restore the boot graphics. + */ +#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ + defined CONFIG_ACPI_BGRT +static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) +{ + u8 r, g, b; + + while (width--) { + b = *src++; + g = *src++; + r = *src++; + *dst++ = (r << si->red_pos) | + (g << si->green_pos) | + (b << si->blue_pos); + } +} + +#ifdef CONFIG_X86 +/* + * On x86 some firmwares use a low non native resolution for the display when + * they have shown some text messages. While keeping the bgrt filled with info + * for the native resolution. If the bgrt image intended for the native + * resolution still fits, it will be displayed very close to the right edge of + * the display looking quite bad. This function checks for this. + */ +static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +{ + static const int default_resolutions[][2] = { + { 800, 600 }, + { 1024, 768 }, + { 1280, 1024 }, + }; + u32 i, right_margin; + + for (i = 0; i < ARRAY_SIZE(default_resolutions); i++) { + if (default_resolutions[i][0] == si->lfb_width && + default_resolutions[i][1] == si->lfb_height) + break; + } + /* If not a default resolution used for textmode, this should be fine */ + if (i >= ARRAY_SIZE(default_resolutions)) + return true; + + /* If the right margin is 5 times smaller then the left one, reject */ + right_margin = si->lfb_width - (bgrt_tab.image_offset_x + bmp_width); + if (right_margin < (bgrt_tab.image_offset_x / 5)) + return false; + + return true; +} +#else +static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +{ + return true; +} +#endif + +static void efifb_show_boot_graphics(struct fb_info *info) +{ + u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y; + struct screen_info *si = &screen_info; + struct bmp_file_header *file_header; + struct bmp_dib_header *dib_header; + void *bgrt_image = NULL; + u8 *dst = info->screen_base; + + if (!bgrt_tab.image_address) { + pr_info("efifb: No BGRT, not showing boot graphics\n"); + return; + } + + /* Avoid flashing the logo if we're going to print std probe messages */ + if (console_loglevel > CONSOLE_LOGLEVEL_QUIET) + return; + + /* bgrt_tab.status is unreliable, so we don't check it */ + + if (si->lfb_depth != 32) { + pr_info("efifb: not 32 bits, not showing boot graphics\n"); + return; + } + + bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size, + MEMREMAP_WB); + if (!bgrt_image) { + pr_warn("efifb: Ignoring BGRT: failed to map image memory\n"); + return; + } + + if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header))) + goto error; + + file_header = bgrt_image; + if (file_header->id != 0x4d42 || file_header->reserved != 0) + goto error; + + dib_header = bgrt_image + sizeof(*file_header); + if (dib_header->dib_header_size != 40 || dib_header->width < 0 || + dib_header->planes != 1 || dib_header->bpp != 24 || + dib_header->compression != 0) + goto error; + + bmp_width = dib_header->width; + bmp_height = abs(dib_header->height); + bmp_pitch = round_up(3 * bmp_width, 4); + screen_pitch = si->lfb_linelength; + + if ((file_header->bitmap_offset + bmp_pitch * bmp_height) > + bgrt_image_size) + goto error; + + if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width || + (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height) + goto error; + + if (!efifb_bgrt_sanity_check(si, bmp_width)) + goto error; + + pr_info("efifb: showing boot graphics\n"); + + for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) { + /* Only background? */ + if (y < bgrt_tab.image_offset_y || + y >= (bgrt_tab.image_offset_y + bmp_height)) { + memset(dst, 0, 4 * si->lfb_width); + continue; + } + + src_y = y - bgrt_tab.image_offset_y; + /* Positive header height means upside down row order */ + if (dib_header->height > 0) + src_y = (bmp_height - 1) - src_y; + + memset(dst, 0, bgrt_tab.image_offset_x * 4); + dst_x = bgrt_tab.image_offset_x; + efifb_copy_bmp(bgrt_image + file_header->bitmap_offset + + src_y * bmp_pitch, + (u32 *)dst + dst_x, bmp_width, si); + dst_x += bmp_width; + memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4); + } + + memunmap(bgrt_image); + return; + +error: + memunmap(bgrt_image); + pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n"); +} +#else +static inline void efifb_show_boot_graphics(struct fb_info *info) {} +#endif + static void efifb_destroy(struct fb_info *info) { if (info->screen_base) { @@ -311,6 +492,8 @@ static int efifb_probe(struct platform_device *dev) goto err_release_fb; } + efifb_show_boot_graphics(info); + pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n", efifb_fix.smem_start, size_remap/1024, size_total/1024); pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c index 1bfd13cbd4e3..bc9eb8afc313 100644 --- a/drivers/video/fbdev/fsl-diu-fb.c +++ b/drivers/video/fbdev/fsl-diu-fb.c @@ -360,6 +360,10 @@ struct mfb_info { * @ad[]: Area Descriptors for each real AOI * @gamma: gamma color table * @cursor: hardware cursor data + * @blank_cursor: blank cursor for hiding cursor + * @next_cursor: scratch space to build load cursor + * @edid_data: EDID information buffer + * @has_edid: whether or not the EDID buffer is valid * * This data structure must be allocated with 32-byte alignment, so that the * internal fields can be aligned properly. @@ -381,6 +385,8 @@ struct fsl_diu_data { __le16 cursor[MAX_CURS * MAX_CURS] __aligned(32); /* Blank cursor data -- used to hide the cursor */ __le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32); + /* Scratch cursor data -- used to build new cursor */ + __le16 next_cursor[MAX_CURS * MAX_CURS] __aligned(32); uint8_t edid_data[EDID_LENGTH]; bool has_edid; } __aligned(32); @@ -1056,13 +1062,17 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor) * FB_CUR_SETSHAPE - the cursor bitmask has changed */ if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) { + /* + * Determine the size of the cursor image data. Normally, + * it's 8x16. + */ unsigned int image_size = - DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height; + DIV_ROUND_UP(cursor->image.width, 8) * + cursor->image.height; unsigned int image_words = DIV_ROUND_UP(image_size, sizeof(uint32_t)); unsigned int bg_idx = cursor->image.bg_color; unsigned int fg_idx = cursor->image.fg_color; - uint8_t buffer[image_size]; uint32_t *image, *source, *mask; uint16_t fg, bg; unsigned int i; @@ -1070,13 +1080,6 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor) if (info->state != FBINFO_STATE_RUNNING) return 0; - /* - * Determine the size of the cursor image data. Normally, - * it's 8x16. - */ - image_size = DIV_ROUND_UP(cursor->image.width, 8) * - cursor->image.height; - bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | ((info->cmap.green[bg_idx] & 0xf8) << 2) | ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | @@ -1088,7 +1091,7 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor) 1 << 15; /* Use 32-bit operations on the data to improve performance */ - image = (uint32_t *)buffer; + image = (uint32_t *)data->next_cursor; source = (uint32_t *)cursor->image.data; mask = (uint32_t *)cursor->mask; diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c index 3b70044773b6..4377e3442638 100644 --- a/drivers/video/fbdev/goldfishfb.c +++ b/drivers/video/fbdev/goldfishfb.c @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/platform_device.h> +#include <linux/acpi.h> enum { FB_GET_WIDTH = 0x00, @@ -124,6 +125,7 @@ static int goldfish_fb_check_var(struct fb_var_screeninfo *var, static int goldfish_fb_set_par(struct fb_info *info) { struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); + if (fb->rotation != fb->fb.var.rotate) { info->fix.line_length = info->var.xres * 2; fb->rotation = fb->fb.var.rotate; @@ -148,13 +150,14 @@ static int goldfish_fb_pan_display(struct fb_var_screeninfo *var, wait_event_timeout(fb->wait, fb->base_update_count != base_update_count, HZ / 15); if (fb->base_update_count == base_update_count) - pr_err("goldfish_fb_pan_display: timeout waiting for base update\n"); + pr_err("%s: timeout waiting for base update\n", __func__); return 0; } static int goldfish_fb_blank(int blank, struct fb_info *info) { struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); + switch (blank) { case FB_BLANK_NORMAL: writel(1, fb->reg_base + FB_SET_BLANK); @@ -234,7 +237,7 @@ static int goldfish_fb_probe(struct platform_device *pdev) fb->fb.var.activate = FB_ACTIVATE_NOW; fb->fb.var.height = readl(fb->reg_base + FB_GET_PHYS_HEIGHT); fb->fb.var.width = readl(fb->reg_base + FB_GET_PHYS_WIDTH); - fb->fb.var.pixclock = 10000; + fb->fb.var.pixclock = 0; fb->fb.var.red.offset = 11; fb->fb.var.red.length = 5; @@ -301,6 +304,7 @@ static int goldfish_fb_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base, fb->fb.fix.smem_start); iounmap(fb->reg_base); + kfree(fb); return 0; } @@ -310,12 +314,19 @@ static const struct of_device_id goldfish_fb_of_match[] = { }; MODULE_DEVICE_TABLE(of, goldfish_fb_of_match); +static const struct acpi_device_id goldfish_fb_acpi_match[] = { + { "GFSH0004", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, goldfish_fb_acpi_match); + static struct platform_driver goldfish_fb_driver = { .probe = goldfish_fb_probe, .remove = goldfish_fb_remove, .driver = { .name = "goldfish_fb", .of_match_table = goldfish_fb_of_match, + .acpi_match_table = ACPI_PTR(goldfish_fb_acpi_match), } }; diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c index 7bc5f6056c77..f6d7b04d6dff 100644 --- a/drivers/video/fbdev/i740fb.c +++ b/drivers/video/fbdev/i740fb.c @@ -429,6 +429,7 @@ static int i740fb_decode_var(const struct fb_var_screeninfo *var, break; case 9 ... 15: bpp = 15; + /* fall through */ case 16: if ((1000000 / var->pixclock) > DACSPEED16) { dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n", diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index 9085e9525341..bb4fee52e501 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -233,7 +233,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, /* check temperature range table checksum */ cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem); if (cksum != mem[cksum_idx]) { @@ -245,7 +245,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, /* check waveform mode table address checksum */ wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF; cksum_idx = wmta + m*4 + 3; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); if (cksum != mem[cksum_idx]) { @@ -257,7 +257,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, /* check waveform temperature table address checksum */ tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF; cksum_idx = tta + trn*4 + 3; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); if (cksum != mem[cksum_idx]) { @@ -270,7 +270,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, metromem buffer. this does runlength decoding of the waveform */ wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF; owfm_idx = wfm_idx; - if (wfm_idx > size) + if (wfm_idx >= size) return -EINVAL; while (wfm_idx < size) { unsigned char rl; @@ -292,7 +292,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, } cksum_idx = wfm_idx; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(owfm_idx, cksum_idx, mem); if (cksum != mem[cksum_idx]) { diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index 585f39efcff6..1c75f4806ed3 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -958,7 +958,7 @@ int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, { int r; - if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM) + if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM) return -EINVAL; if (!notifier_inited) { diff --git a/drivers/video/fbdev/omap2/omapfb/Makefile b/drivers/video/fbdev/omap2/omapfb/Makefile index 602edfed09df..f54c3f56b641 100644 --- a/drivers/video/fbdev/omap2/omapfb/Makefile +++ b/drivers/video/fbdev/omap2/omapfb/Makefile @@ -2,5 +2,5 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o obj-y += dss/ obj-y += displays/ -obj-$(CONFIG_FB_OMAP2) += omapfb.o -omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o +obj-$(CONFIG_FB_OMAP2) += omap2fb.o +omap2fb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c index 3079a3df8c37..47f0459e3551 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c @@ -219,7 +219,7 @@ static int tpd_probe_of(struct platform_device *pdev) static int tpd_probe(struct platform_device *pdev) { - struct omap_dss_device *in, *dssdev; + struct omap_dss_device *dssdev; struct panel_drv_data *ddata; int r; struct gpio_desc *gpio; @@ -238,25 +238,30 @@ static int tpd_probe(struct platform_device *pdev) return -ENODEV; } - gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); goto err_gpio; + } ddata->ct_cp_hpd_gpio = gpio; gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); goto err_gpio; + } ddata->ls_oe_gpio = gpio; gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, GPIOD_IN); - if (IS_ERR(gpio)) + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); goto err_gpio; + } ddata->hpd_gpio = gpio; @@ -268,8 +273,6 @@ static int tpd_probe(struct platform_device *pdev) dssdev->owner = THIS_MODULE; dssdev->port_num = 1; - in = ddata->in; - r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c index fb605aefd9b1..a06d9c25765c 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c @@ -1858,7 +1858,7 @@ static s32 pixinc(int pixels, u8 ps) return 1 - (-pixels + 1) * ps; else BUG(); - return 0; + return 0; } static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, @@ -1905,6 +1905,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY) width = width >> 1; + /* fall through */ case OMAP_DSS_ROT_90: case OMAP_DSS_ROT_270: *offset1 = 0; @@ -1927,6 +1928,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY) width = width >> 1; + /* fall through */ case OMAP_DSS_ROT_90 + 4: case OMAP_DSS_ROT_270 + 4: *offset1 = 0; diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index 3e7887c53d7c..b8b5b4ac0e09 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -893,6 +893,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, / (var->bits_per_pixel >> 2); break; } + /* fall through */ default: screen_width = fix->line_length / (var->bits_per_pixel >> 3); break; diff --git a/drivers/video/fbdev/pm2fb.c b/drivers/video/fbdev/pm2fb.c index bd6c2f5f6095..1dcf02e12af4 100644 --- a/drivers/video/fbdev/pm2fb.c +++ b/drivers/video/fbdev/pm2fb.c @@ -233,8 +233,10 @@ static u32 to3264(u32 timing, int bpp, int is64) switch (bpp) { case 24: timing *= 3; + /* fall through */ case 8: timing >>= 1; + /* fall through */ case 16: timing >>= 1; case 32: diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c index 0955622a1227..69cfb337c857 100644 --- a/drivers/video/fbdev/pxa3xx-gcu.c +++ b/drivers/video/fbdev/pxa3xx-gcu.c @@ -44,6 +44,7 @@ #include <linux/clk.h> #include <linux/fs.h> #include <linux/io.h> +#include <linux/of.h> #include "pxa3xx-gcu.h" @@ -703,11 +704,20 @@ static int pxa3xx_gcu_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id pxa3xx_gcu_of_match[] = { + { .compatible = "marvell,pxa300-gcu", }, + { } +}; +MODULE_DEVICE_TABLE(of, pxa3xx_gcu_of_match); +#endif + static struct platform_driver pxa3xx_gcu_driver = { .probe = pxa3xx_gcu_probe, .remove = pxa3xx_gcu_remove, .driver = { .name = DRV_NAME, + .of_match_table = of_match_ptr(pxa3xx_gcu_of_match), }, }; diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index 76722a59f55e..bbed039617a4 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -56,6 +56,7 @@ #include <linux/freezer.h> #include <linux/console.h> #include <linux/of_graph.h> +#include <linux/regulator/consumer.h> #include <video/of_display_timing.h> #include <video/videomode.h> @@ -1423,6 +1424,21 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on) if (fbi->lcd_power) fbi->lcd_power(on, &fbi->fb.var); + + if (fbi->lcd_supply && fbi->lcd_supply_enabled != on) { + int ret; + + if (on) + ret = regulator_enable(fbi->lcd_supply); + else + ret = regulator_disable(fbi->lcd_supply); + + if (ret < 0) + pr_warn("Unable to %s LCD supply regulator: %d\n", + on ? "enable" : "disable", ret); + else + fbi->lcd_supply_enabled = on; + } } static void pxafb_enable_controller(struct pxafb_info *fbi) @@ -1799,19 +1815,17 @@ static struct pxafb_info *pxafb_init_fbinfo(struct device *dev, void *addr; /* Alloc the pxafb_info and pseudo_palette in one step */ - fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); + fbi = devm_kzalloc(dev, sizeof(struct pxafb_info) + sizeof(u32) * 16, + GFP_KERNEL); if (!fbi) - return NULL; + return ERR_PTR(-ENOMEM); - memset(fbi, 0, sizeof(struct pxafb_info)); fbi->dev = dev; fbi->inf = inf; - fbi->clk = clk_get(dev, NULL); - if (IS_ERR(fbi->clk)) { - kfree(fbi); - return NULL; - } + fbi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(fbi->clk)) + return ERR_CAST(fbi->clk); strcpy(fbi->fb.fix.id, PXA_NAME); @@ -2128,8 +2142,9 @@ static int of_get_pxafb_display(struct device *dev, struct device_node *disp, return -EINVAL; ret = -ENOMEM; - info->modes = kmalloc_array(timings->num_timings, - sizeof(info->modes[0]), GFP_KERNEL); + info->modes = devm_kcalloc(dev, timings->num_timings, + sizeof(info->modes[0]), + GFP_KERNEL); if (!info->modes) goto out; info->num_modes = timings->num_timings; @@ -2288,10 +2303,9 @@ static int pxafb_probe(struct platform_device *dev) } fbi = pxafb_init_fbinfo(&dev->dev, inf); - if (!fbi) { - /* only reason for pxafb_init_fbinfo to fail is kmalloc */ + if (IS_ERR(fbi)) { dev_err(&dev->dev, "Failed to initialize framebuffer device\n"); - ret = -ENOMEM; + ret = PTR_ERR(fbi); goto failed; } @@ -2301,25 +2315,26 @@ static int pxafb_probe(struct platform_device *dev) fbi->backlight_power = inf->pxafb_backlight_power; fbi->lcd_power = inf->pxafb_lcd_power; + fbi->lcd_supply = devm_regulator_get_optional(&dev->dev, "lcd"); + if (IS_ERR(fbi->lcd_supply)) { + if (PTR_ERR(fbi->lcd_supply) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + fbi->lcd_supply = NULL; + } + r = platform_get_resource(dev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&dev->dev, "no I/O memory resource defined\n"); ret = -ENODEV; - goto failed_fbi; - } - - r = request_mem_region(r->start, resource_size(r), dev->name); - if (r == NULL) { - dev_err(&dev->dev, "failed to request I/O memory\n"); - ret = -EBUSY; - goto failed_fbi; + goto failed; } - fbi->mmio_base = ioremap(r->start, resource_size(r)); - if (fbi->mmio_base == NULL) { - dev_err(&dev->dev, "failed to map I/O memory\n"); + fbi->mmio_base = devm_ioremap_resource(&dev->dev, r); + if (IS_ERR(fbi->mmio_base)) { + dev_err(&dev->dev, "failed to get I/O memory\n"); ret = -EBUSY; - goto failed_free_res; + goto failed; } fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff)); @@ -2328,7 +2343,7 @@ static int pxafb_probe(struct platform_device *dev) if (fbi->dma_buff == NULL) { dev_err(&dev->dev, "failed to allocate memory for DMA\n"); ret = -ENOMEM; - goto failed_free_io; + goto failed; } ret = pxafb_init_video_memory(fbi); @@ -2345,7 +2360,7 @@ static int pxafb_probe(struct platform_device *dev) goto failed_free_mem; } - ret = request_irq(irq, pxafb_handle_irq, 0, "LCD", fbi); + ret = devm_request_irq(&dev->dev, irq, pxafb_handle_irq, 0, "LCD", fbi); if (ret) { dev_err(&dev->dev, "request_irq failed: %d\n", ret); ret = -EBUSY; @@ -2355,7 +2370,7 @@ static int pxafb_probe(struct platform_device *dev) ret = pxafb_smart_init(fbi); if (ret) { dev_err(&dev->dev, "failed to initialize smartpanel\n"); - goto failed_free_irq; + goto failed_free_mem; } /* @@ -2365,13 +2380,13 @@ static int pxafb_probe(struct platform_device *dev) ret = pxafb_check_var(&fbi->fb.var, &fbi->fb); if (ret) { dev_err(&dev->dev, "failed to get suitable mode\n"); - goto failed_free_irq; + goto failed_free_mem; } ret = pxafb_set_par(&fbi->fb); if (ret) { dev_err(&dev->dev, "Failed to set parameters\n"); - goto failed_free_irq; + goto failed_free_mem; } platform_set_drvdata(dev, fbi); @@ -2404,20 +2419,11 @@ static int pxafb_probe(struct platform_device *dev) failed_free_cmap: if (fbi->fb.cmap.len) fb_dealloc_cmap(&fbi->fb.cmap); -failed_free_irq: - free_irq(irq, fbi); failed_free_mem: free_pages_exact(fbi->video_mem, fbi->video_mem_size); failed_free_dma: dma_free_coherent(&dev->dev, fbi->dma_buff_size, fbi->dma_buff, fbi->dma_buff_phys); -failed_free_io: - iounmap(fbi->mmio_base); -failed_free_res: - release_mem_region(r->start, resource_size(r)); -failed_fbi: - clk_put(fbi->clk); - kfree(fbi); failed: return ret; } @@ -2425,8 +2431,6 @@ failed: static int pxafb_remove(struct platform_device *dev) { struct pxafb_info *fbi = platform_get_drvdata(dev); - struct resource *r; - int irq; struct fb_info *info; if (!fbi) @@ -2442,22 +2446,11 @@ static int pxafb_remove(struct platform_device *dev) if (fbi->fb.cmap.len) fb_dealloc_cmap(&fbi->fb.cmap); - irq = platform_get_irq(dev, 0); - free_irq(irq, fbi); - free_pages_exact(fbi->video_mem, fbi->video_mem_size); dma_free_wc(&dev->dev, fbi->dma_buff_size, fbi->dma_buff, fbi->dma_buff_phys); - iounmap(fbi->mmio_base); - - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - - clk_put(fbi->clk); - kfree(fbi); - return 0; } diff --git a/drivers/video/fbdev/pxafb.h b/drivers/video/fbdev/pxafb.h index 5dc414e26fc8..b641289c8a99 100644 --- a/drivers/video/fbdev/pxafb.h +++ b/drivers/video/fbdev/pxafb.h @@ -165,6 +165,9 @@ struct pxafb_info { struct notifier_block freq_policy; #endif + struct regulator *lcd_supply; + bool lcd_supply_enabled; + void (*lcd_power)(int, struct fb_var_screeninfo *); void (*backlight_power)(int); diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index a3c44ecf4523..9a9d748b07f2 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -27,8 +27,8 @@ #include <linux/platform_data/simplefb.h> #include <linux/platform_device.h> #include <linux/clk.h> -#include <linux/clk-provider.h> #include <linux/of.h> +#include <linux/of_clk.h> #include <linux/of_platform.h> #include <linux/parser.h> #include <linux/regulator/consumer.h> diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c index dec1fed9880e..fbbf26b170f7 100644 --- a/drivers/video/fbdev/tdfxfb.c +++ b/drivers/video/fbdev/tdfxfb.c @@ -522,6 +522,7 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) case 32: var->transp.offset = 24; var->transp.length = 8; + /* fall through */ case 24: var->red.offset = 16; var->green.offset = 8; diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 284706184b1b..f4b745590600 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -777,9 +777,6 @@ static int get_nativex(struct tridentfb_par *par) case 3: x = 800; y = 600; break; - case 4: - x = 1400; y = 1050; - break; case 1: default: x = 640; y = 480; diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index f365d4862015..afbd6101c78e 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -25,8 +25,8 @@ #include <linux/fb.h> #include <linux/vmalloc.h> #include <linux/slab.h> -#include <linux/prefetch.h> #include <linux/delay.h> +#include <asm/unaligned.h> #include <video/udlfb.h> #include "edid.h" @@ -72,6 +72,13 @@ static bool fb_defio = 1; /* Detect mmap writes using page faults */ static bool shadow = 1; /* Optionally disable shadow framebuffer */ static int pixel_limit; /* Optionally force a pixel resolution limit */ +struct dlfb_deferred_free { + struct list_head list; + void *mem; +}; + +static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len); + /* dlfb keeps a list of urbs for efficient bulk transfers */ static void dlfb_urb_completion(struct urb *urb); static struct urb *dlfb_get_urb(struct dlfb_data *dlfb); @@ -367,9 +374,6 @@ static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes) int start = width; int end = width; - prefetch((void *) front); - prefetch((void *) back); - for (j = 0; j < width; j++) { if (back[j] != front[j]) { start = j; @@ -423,7 +427,9 @@ static void dlfb_compress_hline( const uint16_t *const pixel_end, uint32_t *device_address_ptr, uint8_t **command_buffer_ptr, - const uint8_t *const cmd_buffer_end) + const uint8_t *const cmd_buffer_end, + unsigned long back_buffer_offset, + int *ident_ptr) { const uint16_t *pixel = *pixel_start_ptr; uint32_t dev_addr = *device_address_ptr; @@ -436,7 +442,13 @@ static void dlfb_compress_hline( const uint16_t *raw_pixel_start = NULL; const uint16_t *cmd_pixel_start, *cmd_pixel_end = NULL; - prefetchw((void *) cmd); /* pull in one cache line at least */ + if (back_buffer_offset && + *pixel == *(u16 *)((u8 *)pixel + back_buffer_offset)) { + pixel++; + dev_addr += BPP; + (*ident_ptr)++; + continue; + } *cmd++ = 0xAF; *cmd++ = 0x6B; @@ -450,29 +462,39 @@ static void dlfb_compress_hline( raw_pixels_count_byte = cmd++; /* we'll know this later */ raw_pixel_start = pixel; - cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1, - min((int)(pixel_end - pixel), - (int)(cmd_buffer_end - cmd) / BPP)); + cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL, + (unsigned long)(pixel_end - pixel), + (unsigned long)(cmd_buffer_end - 1 - cmd) / BPP); - prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * BPP); + if (back_buffer_offset) { + /* note: the framebuffer may change under us, so we must test for underflow */ + while (cmd_pixel_end - 1 > pixel && + *(cmd_pixel_end - 1) == *(u16 *)((u8 *)(cmd_pixel_end - 1) + back_buffer_offset)) + cmd_pixel_end--; + } while (pixel < cmd_pixel_end) { const uint16_t * const repeating_pixel = pixel; + u16 pixel_value = *pixel; - *cmd++ = *pixel >> 8; - *cmd++ = *pixel; + put_unaligned_be16(pixel_value, cmd); + if (back_buffer_offset) + *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value; + cmd += 2; pixel++; if (unlikely((pixel < cmd_pixel_end) && - (*pixel == *repeating_pixel))) { + (*pixel == pixel_value))) { /* go back and fill in raw pixel count */ *raw_pixels_count_byte = ((repeating_pixel - raw_pixel_start) + 1) & 0xFF; - while ((pixel < cmd_pixel_end) - && (*pixel == *repeating_pixel)) { + do { + if (back_buffer_offset) + *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value; pixel++; - } + } while ((pixel < cmd_pixel_end) && + (*pixel == pixel_value)); /* immediately after raw data is repeat byte */ *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF; @@ -486,13 +508,16 @@ static void dlfb_compress_hline( if (pixel > raw_pixel_start) { /* finalize last RAW span */ *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF; + } else { + /* undo unused byte */ + cmd--; } *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF; - dev_addr += (pixel - cmd_pixel_start) * BPP; + dev_addr += (u8 *)pixel - (u8 *)cmd_pixel_start; } - if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { + if (cmd_buffer_end - MIN_RLX_CMD_BYTES <= cmd) { /* Fill leftover bytes with no-ops */ if (cmd_buffer_end > cmd) memset(cmd, 0xAF, cmd_buffer_end - cmd); @@ -520,6 +545,7 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr, struct urb *urb = *urb_ptr; u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; + unsigned long back_buffer_offset = 0; line_start = (u8 *) (front + byte_offset); next_pixel = line_start; @@ -530,6 +556,8 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr, const u8 *back_start = (u8 *) (dlfb->backing_buffer + byte_offset); + back_buffer_offset = (unsigned long)back_start - (unsigned long)line_start; + *ident_ptr += dlfb_trim_hline(back_start, &next_pixel, &byte_width); @@ -538,16 +566,14 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr, dev_addr += offset; back_start += offset; line_start += offset; - - memcpy((char *)back_start, (char *) line_start, - byte_width); } while (next_pixel < line_end) { dlfb_compress_hline((const uint16_t **) &next_pixel, (const uint16_t *) line_end, &dev_addr, - (u8 **) &cmd, (u8 *) cmd_end); + (u8 **) &cmd, (u8 *) cmd_end, back_buffer_offset, + ident_ptr); if (cmd >= cmd_end) { int len = cmd - (u8 *) urb->transfer_buffer; @@ -610,8 +636,11 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, } if (cmd > (char *) urb->transfer_buffer) { + int len; + if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) + *cmd++ = 0xAF; /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; + len = cmd - (char *) urb->transfer_buffer; ret = dlfb_submit_urb(dlfb, urb, len); bytes_sent += len; } else @@ -735,8 +764,11 @@ static void dlfb_dpy_deferred_io(struct fb_info *info, } if (cmd > (char *) urb->transfer_buffer) { + int len; + if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) + *cmd++ = 0xAF; /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; + len = cmd - (char *) urb->transfer_buffer; dlfb_submit_urb(dlfb, urb, len); bytes_sent += len; } else @@ -917,19 +949,17 @@ static void dlfb_free(struct kref *kref) { struct dlfb_data *dlfb = container_of(kref, struct dlfb_data, kref); + while (!list_empty(&dlfb->deferred_free)) { + struct dlfb_deferred_free *d = list_entry(dlfb->deferred_free.next, struct dlfb_deferred_free, list); + list_del(&d->list); + vfree(d->mem); + kfree(d); + } vfree(dlfb->backing_buffer); kfree(dlfb->edid); kfree(dlfb); } -static void dlfb_release_urb_work(struct work_struct *work) -{ - struct urb_node *unode = container_of(work, struct urb_node, - release_urb_work.work); - - up(&unode->dlfb->urbs.limit_sem); -} - static void dlfb_free_framebuffer(struct dlfb_data *dlfb) { struct fb_info *info = dlfb->info; @@ -1018,10 +1048,6 @@ static int dlfb_ops_check_var(struct fb_var_screeninfo *var, struct fb_videomode mode; struct dlfb_data *dlfb = info->par; - /* TODO: support dynamically changing framebuffer size */ - if ((var->xres * var->yres * 2) > info->fix.smem_len) - return -EINVAL; - /* set device-specific elements of var unrelated to mode */ dlfb_var_color_format(var); @@ -1039,22 +1065,42 @@ static int dlfb_ops_set_par(struct fb_info *info) int result; u16 *pix_framebuffer; int i; + struct fb_var_screeninfo fvs; + u32 line_length = info->var.xres * (info->var.bits_per_pixel / 8); + + /* clear the activate field because it causes spurious miscompares */ + fvs = info->var; + fvs.activate = 0; + fvs.vmode &= ~FB_VMODE_SMOOTH_XPAN; + + if (!memcmp(&dlfb->current_mode, &fvs, sizeof(struct fb_var_screeninfo))) + return 0; + + result = dlfb_realloc_framebuffer(dlfb, info, info->var.yres * line_length); + if (result) + return result; result = dlfb_set_video_mode(dlfb, &info->var); - if ((result == 0) && (dlfb->fb_count == 0)) { + if (result) + return result; + + dlfb->current_mode = fvs; + info->fix.line_length = line_length; + + if (dlfb->fb_count == 0) { /* paint greenscreen */ pix_framebuffer = (u16 *) info->screen_base; for (i = 0; i < info->fix.smem_len / 2; i++) pix_framebuffer[i] = 0x37e6; - - dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres, - info->screen_base); } - return result; + dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres, + info->screen_base); + + return 0; } /* To fonzi the jukebox (e.g. make blanking changes take effect) */ @@ -1129,21 +1175,29 @@ static struct fb_ops dlfb_ops = { }; +static void dlfb_deferred_vfree(struct dlfb_data *dlfb, void *mem) +{ + struct dlfb_deferred_free *d = kmalloc(sizeof(struct dlfb_deferred_free), GFP_KERNEL); + if (!d) + return; + d->mem = mem; + list_add(&d->list, &dlfb->deferred_free); +} + /* * Assumes &info->lock held by caller * Assumes no active clients have framebuffer open */ -static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info) +static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len) { - int old_len = info->fix.smem_len; - int new_len; - unsigned char *old_fb = info->screen_base; + u32 old_len = info->fix.smem_len; + const void *old_fb = (const void __force *)info->screen_base; unsigned char *new_fb; unsigned char *new_back = NULL; - new_len = info->fix.line_length * info->var.yres; + new_len = PAGE_ALIGN(new_len); - if (PAGE_ALIGN(new_len) > old_len) { + if (new_len > old_len) { /* * Alloc system memory for virtual framebuffer */ @@ -1152,14 +1206,15 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info dev_err(info->dev, "Virtual framebuffer alloc failed\n"); return -ENOMEM; } + memset(new_fb, 0xff, new_len); if (info->screen_base) { memcpy(new_fb, old_fb, old_len); - vfree(info->screen_base); + dlfb_deferred_vfree(dlfb, (void __force *)info->screen_base); } - info->screen_base = new_fb; - info->fix.smem_len = PAGE_ALIGN(new_len); + info->screen_base = (char __iomem *)new_fb; + info->fix.smem_len = new_len; info->fix.smem_start = (unsigned long) new_fb; info->flags = udlfb_info_flags; @@ -1175,7 +1230,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info dev_info(info->dev, "No shadow/backing buffer allocated\n"); else { - vfree(dlfb->backing_buffer); + dlfb_deferred_vfree(dlfb, dlfb->backing_buffer); dlfb->backing_buffer = new_back; } } @@ -1327,11 +1382,6 @@ static int dlfb_setup_modes(struct dlfb_data *dlfb, * with mode size info, we can now alloc our framebuffer. */ memcpy(&info->fix, &dlfb_fix, sizeof(dlfb_fix)); - info->fix.line_length = info->var.xres * - (info->var.bits_per_pixel / 8); - - result = dlfb_realloc_framebuffer(dlfb, info); - } else result = -EINVAL; @@ -1419,7 +1469,10 @@ static ssize_t edid_store( if (!dlfb->edid || memcmp(src, dlfb->edid, src_size)) return -EINVAL; - dlfb_ops_set_par(fb_info); + ret = dlfb_ops_set_par(fb_info); + if (ret) + return ret; + return src_size; } @@ -1579,6 +1632,7 @@ static int dlfb_usb_probe(struct usb_interface *intf, } kref_init(&dlfb->kref); /* matching kref_put in usb .disconnect fn */ + INIT_LIST_HEAD(&dlfb->deferred_free); dlfb->udev = usbdev; usb_set_intfdata(intf, dlfb); @@ -1649,7 +1703,8 @@ static void dlfb_init_framebuffer_work(struct work_struct *work) dlfb->info = info; info->par = dlfb; info->pseudo_palette = dlfb->pseudo_palette; - info->fbops = &dlfb_ops; + dlfb->ops = dlfb_ops; + info->fbops = &dlfb->ops; retval = fb_alloc_cmap(&info->cmap, 256, 0); if (retval < 0) { @@ -1675,7 +1730,9 @@ static void dlfb_init_framebuffer_work(struct work_struct *work) dlfb_select_std_channel(dlfb); dlfb_ops_check_var(&info->var, info); - dlfb_ops_set_par(info); + retval = dlfb_ops_set_par(info); + if (retval) + goto error; retval = register_framebuffer(info); if (retval < 0) { @@ -1789,14 +1846,7 @@ static void dlfb_urb_completion(struct urb *urb) dlfb->urbs.available++; spin_unlock_irqrestore(&dlfb->urbs.lock, flags); - /* - * When using fb_defio, we deadlock if up() is called - * while another is waiting. So queue to another process. - */ - if (fb_defio) - schedule_delayed_work(&unode->release_urb_work, 0); - else - up(&dlfb->urbs.limit_sem); + up(&dlfb->urbs.limit_sem); } static void dlfb_free_urb_list(struct dlfb_data *dlfb) @@ -1805,23 +1855,17 @@ static void dlfb_free_urb_list(struct dlfb_data *dlfb) struct list_head *node; struct urb_node *unode; struct urb *urb; - int ret; - unsigned long flags; /* keep waiting and freeing, until we've got 'em all */ while (count--) { + down(&dlfb->urbs.limit_sem); - /* Getting interrupted means a leak, but ok at disconnect */ - ret = down_interruptible(&dlfb->urbs.limit_sem); - if (ret) - break; - - spin_lock_irqsave(&dlfb->urbs.lock, flags); + spin_lock_irq(&dlfb->urbs.lock); node = dlfb->urbs.list.next; /* have reserved one with sem */ list_del_init(node); - spin_unlock_irqrestore(&dlfb->urbs.lock, flags); + spin_unlock_irq(&dlfb->urbs.lock); unode = list_entry(node, struct urb_node, entry); urb = unode->urb; @@ -1838,25 +1882,27 @@ static void dlfb_free_urb_list(struct dlfb_data *dlfb) static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size) { - int i = 0; struct urb *urb; struct urb_node *unode; char *buf; + size_t wanted_size = count * size; spin_lock_init(&dlfb->urbs.lock); +retry: dlfb->urbs.size = size; INIT_LIST_HEAD(&dlfb->urbs.list); - while (i < count) { + sema_init(&dlfb->urbs.limit_sem, 0); + dlfb->urbs.count = 0; + dlfb->urbs.available = 0; + + while (dlfb->urbs.count * size < wanted_size) { unode = kzalloc(sizeof(*unode), GFP_KERNEL); if (!unode) break; unode->dlfb = dlfb; - INIT_DELAYED_WORK(&unode->release_urb_work, - dlfb_release_urb_work); - urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { kfree(unode); @@ -1864,11 +1910,16 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size) } unode->urb = urb; - buf = usb_alloc_coherent(dlfb->udev, MAX_TRANSFER, GFP_KERNEL, + buf = usb_alloc_coherent(dlfb->udev, size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { kfree(unode); usb_free_urb(urb); + if (size > PAGE_SIZE) { + size /= 2; + dlfb_free_urb_list(dlfb); + goto retry; + } break; } @@ -1879,14 +1930,12 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size) list_add_tail(&unode->entry, &dlfb->urbs.list); - i++; + up(&dlfb->urbs.limit_sem); + dlfb->urbs.count++; + dlfb->urbs.available++; } - sema_init(&dlfb->urbs.limit_sem, i); - dlfb->urbs.count = i; - dlfb->urbs.available = i; - - return i; + return dlfb->urbs.count; } static struct urb *dlfb_get_urb(struct dlfb_data *dlfb) @@ -1894,7 +1943,6 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dlfb) int ret; struct list_head *entry; struct urb_node *unode; - unsigned long flags; /* Wait for an in-flight buffer to complete and get re-queued */ ret = down_timeout(&dlfb->urbs.limit_sem, GET_URB_TIMEOUT); @@ -1906,14 +1954,14 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dlfb) return NULL; } - spin_lock_irqsave(&dlfb->urbs.lock, flags); + spin_lock_irq(&dlfb->urbs.lock); BUG_ON(list_empty(&dlfb->urbs.list)); /* reserved one with limit_sem */ entry = dlfb->urbs.list.next; list_del_init(entry); dlfb->urbs.available--; - spin_unlock_irqrestore(&dlfb->urbs.lock, flags); + spin_unlock_irq(&dlfb->urbs.lock); unode = list_entry(entry, struct urb_node, entry); return unode->urb; diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c index 5d21ff436ec8..b9305d73a1e5 100644 --- a/drivers/video/fbdev/via/lcd.c +++ b/drivers/video/fbdev/via/lcd.c @@ -758,6 +758,7 @@ static void set_lcd_output_path(int set_iga, int output_interface) viaparinfo->chip_info->gfx_chip_name)) viafb_write_reg_mask(CR97, VIACR, 0x84, BIT7 + BIT2 + BIT1 + BIT0); + /* fall through */ case INTERFACE_DVP0: case INTERFACE_DVP1: case INTERFACE_DFP_HIGH: diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c index d2f785068ef4..7bb7e90b8f00 100644 --- a/drivers/video/fbdev/via/viafbdev.c +++ b/drivers/video/fbdev/via/viafbdev.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/compiler.h> #include <linux/module.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -1468,7 +1469,7 @@ static const struct file_operations viafb_vt1636_proc_fops = { #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ -static int viafb_sup_odev_proc_show(struct seq_file *m, void *v) +static int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v) { via_odev_to_seq(m, supported_odev_map[ viaparinfo->shared->chip_info.gfx_chip_name]); diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 3988c0914322..d1c1f6283729 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -27,7 +27,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/balloon_compaction.h> -#include <linux/oom.h> #include <linux/wait.h> #include <linux/mm.h> #include <linux/mount.h> @@ -40,13 +39,8 @@ */ #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT) #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256 -#define OOM_VBALLOON_DEFAULT_PAGES 256 #define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80 -static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES; -module_param(oom_pages, int, S_IRUSR | S_IWUSR); -MODULE_PARM_DESC(oom_pages, "pages to free on OOM"); - #ifdef CONFIG_BALLOON_COMPACTION static struct vfsmount *balloon_mnt; #endif @@ -86,8 +80,8 @@ struct virtio_balloon { /* Memory statistics */ struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; - /* To register callback in oom notifier call chain */ - struct notifier_block nb; + /* To register a shrinker to shrink memory upon memory pressure */ + struct shrinker shrinker; }; static struct virtio_device_id id_table[] = { @@ -365,38 +359,6 @@ static void update_balloon_size(struct virtio_balloon *vb) &actual); } -/* - * virtballoon_oom_notify - release pages when system is under severe - * memory pressure (called from out_of_memory()) - * @self : notifier block struct - * @dummy: not used - * @parm : returned - number of freed pages - * - * The balancing of memory by use of the virtio balloon should not cause - * the termination of processes while there are pages in the balloon. - * If virtio balloon manages to release some memory, it will make the - * system return and retry the allocation that forced the OOM killer - * to run. - */ -static int virtballoon_oom_notify(struct notifier_block *self, - unsigned long dummy, void *parm) -{ - struct virtio_balloon *vb; - unsigned long *freed; - unsigned num_freed_pages; - - vb = container_of(self, struct virtio_balloon, nb); - if (!virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) - return NOTIFY_OK; - - freed = parm; - num_freed_pages = leak_balloon(vb, oom_pages); - update_balloon_size(vb); - *freed += num_freed_pages; - - return NOTIFY_OK; -} - static void update_balloon_stats_func(struct work_struct *work) { struct virtio_balloon *vb; @@ -455,9 +417,13 @@ static int init_vqs(struct virtio_balloon *vb) num_stats = update_balloon_stats(vb); sg_init_one(&sg, vb->stats, sizeof(vb->stats[0]) * num_stats); - if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL) - < 0) - BUG(); + err = virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, + GFP_KERNEL); + if (err) { + dev_warn(&vb->vdev->dev, "%s: add stat_vq failed\n", + __func__); + return err; + } virtqueue_kick(vb->stats_vq); } return 0; @@ -546,6 +512,52 @@ static struct file_system_type balloon_fs = { #endif /* CONFIG_BALLOON_COMPACTION */ +static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker, + struct shrink_control *sc) +{ + unsigned long pages_to_free, pages_freed = 0; + struct virtio_balloon *vb = container_of(shrinker, + struct virtio_balloon, shrinker); + + pages_to_free = sc->nr_to_scan * VIRTIO_BALLOON_PAGES_PER_PAGE; + + /* + * One invocation of leak_balloon can deflate at most + * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it + * multiple times to deflate pages till reaching pages_to_free. + */ + while (vb->num_pages && pages_to_free) { + pages_to_free -= pages_freed; + pages_freed += leak_balloon(vb, pages_to_free); + } + update_balloon_size(vb); + + return pages_freed / VIRTIO_BALLOON_PAGES_PER_PAGE; +} + +static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct virtio_balloon *vb = container_of(shrinker, + struct virtio_balloon, shrinker); + + return vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE; +} + +static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb) +{ + unregister_shrinker(&vb->shrinker); +} + +static int virtio_balloon_register_shrinker(struct virtio_balloon *vb) +{ + vb->shrinker.scan_objects = virtio_balloon_shrinker_scan; + vb->shrinker.count_objects = virtio_balloon_shrinker_count; + vb->shrinker.seeks = DEFAULT_SEEKS; + + return register_shrinker(&vb->shrinker); +} + static int virtballoon_probe(struct virtio_device *vdev) { struct virtio_balloon *vb; @@ -557,7 +569,7 @@ static int virtballoon_probe(struct virtio_device *vdev) return -EINVAL; } - vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); + vdev->priv = vb = kzalloc(sizeof(*vb), GFP_KERNEL); if (!vb) { err = -ENOMEM; goto out; @@ -566,8 +578,6 @@ static int virtballoon_probe(struct virtio_device *vdev) INIT_WORK(&vb->update_balloon_stats_work, update_balloon_stats_func); INIT_WORK(&vb->update_balloon_size_work, update_balloon_size_func); spin_lock_init(&vb->stop_update_lock); - vb->stop_update = false; - vb->num_pages = 0; mutex_init(&vb->balloon_lock); init_waitqueue_head(&vb->acked); vb->vdev = vdev; @@ -578,17 +588,10 @@ static int virtballoon_probe(struct virtio_device *vdev) if (err) goto out_free_vb; - vb->nb.notifier_call = virtballoon_oom_notify; - vb->nb.priority = VIRTBALLOON_OOM_NOTIFY_PRIORITY; - err = register_oom_notifier(&vb->nb); - if (err < 0) - goto out_del_vqs; - #ifdef CONFIG_BALLOON_COMPACTION balloon_mnt = kern_mount(&balloon_fs); if (IS_ERR(balloon_mnt)) { err = PTR_ERR(balloon_mnt); - unregister_oom_notifier(&vb->nb); goto out_del_vqs; } @@ -597,13 +600,19 @@ static int virtballoon_probe(struct virtio_device *vdev) if (IS_ERR(vb->vb_dev_info.inode)) { err = PTR_ERR(vb->vb_dev_info.inode); kern_unmount(balloon_mnt); - unregister_oom_notifier(&vb->nb); - vb->vb_dev_info.inode = NULL; goto out_del_vqs; } vb->vb_dev_info.inode->i_mapping->a_ops = &balloon_aops; #endif - + /* + * We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a + * shrinker needs to be registered to relieve memory pressure. + */ + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) { + err = virtio_balloon_register_shrinker(vb); + if (err) + goto out_del_vqs; + } virtio_device_ready(vdev); if (towards_target(vb)) @@ -635,8 +644,8 @@ static void virtballoon_remove(struct virtio_device *vdev) { struct virtio_balloon *vb = vdev->priv; - unregister_oom_notifier(&vb->nb); - + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) + virtio_balloon_unregister_shrinker(vb); spin_lock_irq(&vb->stop_update_lock); vb->stop_update = true; spin_unlock_irq(&vb->stop_update_lock); diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 67763d3c7abf..4cd9ea5c75be 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -397,9 +397,23 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, /* Activate the queue */ writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); if (vm_dev->version == 1) { + u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT; + + /* + * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something + * that doesn't fit in 32bit, fail the setup rather than + * pretending to be successful. + */ + if (q_pfn >> 32) { + dev_err(&vdev->dev, + "platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n", + 0x1ULL << (32 + PAGE_SHIFT - 30)); + err = -E2BIG; + goto error_bad_pfn; + } + writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); - writel(virtqueue_get_desc_addr(vq) >> PAGE_SHIFT, - vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); + writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); } else { u64 addr; @@ -430,6 +444,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, return vq; +error_bad_pfn: + vring_del_virtqueue(vq); error_new_virtqueue: if (vm_dev->version == 1) { writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index 2780886e8ba3..de062fb201bc 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -122,6 +122,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, struct virtqueue *vq; u16 num; int err; + u64 q_pfn; /* Select the queue we're interested in */ iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL); @@ -141,9 +142,17 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, if (!vq) return ERR_PTR(-ENOMEM); + q_pfn = virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; + if (q_pfn >> 32) { + dev_err(&vp_dev->pci_dev->dev, + "platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n", + 0x1ULL << (32 + PAGE_SHIFT - 30)); + err = -E2BIG; + goto out_del_vq; + } + /* activate the queue */ - iowrite32(virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT, - vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); + iowrite32(q_pfn, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); vq->priv = (void __force *)vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY; @@ -160,6 +169,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, out_deactivate: iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); +out_del_vq: vring_del_virtqueue(vq); return ERR_PTR(err); } diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 7931231d8e80..e22fdeddada1 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -100,18 +100,6 @@ config W1_SLAVE_DS2438 Say Y here if you want to use a 1-wire DS2438 Smart Battery Monitor device support -config W1_SLAVE_DS2760 - tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" - help - If you enable this you will have the DS2760 battery monitor - chip support. - - The battery monitor chip is used in many batteries/devices - as the one who is responsible for charging/discharging/monitoring - Li+ batteries. - - If you are unsure, say N. - config W1_SLAVE_DS2780 tristate "Dallas 2780 battery monitor chip" help diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index d5f4f4d5b9e5..eab29f151413 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o obj-$(CONFIG_W1_SLAVE_DS2805) += w1_ds2805.o obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o -obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c deleted file mode 100644 index 26168abfb8b8..000000000000 --- a/drivers/w1/slaves/w1_ds2760.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 1-Wire implementation for the ds2760 chip - * - * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> - * - * Use consistent with the GNU GPL is permitted, - * provided that this copyright notice is - * preserved in its entirety in all copies and derived works. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/types.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/idr.h> -#include <linux/gfp.h> - -#include <linux/w1.h> - -#include "w1_ds2760.h" - -#define W1_FAMILY_DS2760 0x30 - -static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count, - int io) -{ - struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - - if (!dev) - return 0; - - mutex_lock(&sl->master->bus_mutex); - - if (addr > DS2760_DATA_SIZE || addr < 0) { - count = 0; - goto out; - } - if (addr + count > DS2760_DATA_SIZE) - count = DS2760_DATA_SIZE - addr; - - if (!w1_reset_select_slave(sl)) { - if (!io) { - w1_write_8(sl->master, W1_DS2760_READ_DATA); - w1_write_8(sl->master, addr); - count = w1_read_block(sl->master, buf, count); - } else { - w1_write_8(sl->master, W1_DS2760_WRITE_DATA); - w1_write_8(sl->master, addr); - w1_write_block(sl->master, buf, count); - /* XXX w1_write_block returns void, not n_written */ - } - } - -out: - mutex_unlock(&sl->master->bus_mutex); - - return count; -} - -int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count) -{ - return w1_ds2760_io(dev, buf, addr, count, 0); -} -EXPORT_SYMBOL(w1_ds2760_read); - -int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count) -{ - return w1_ds2760_io(dev, buf, addr, count, 1); -} -EXPORT_SYMBOL(w1_ds2760_write); - -static int w1_ds2760_eeprom_cmd(struct device *dev, int addr, int cmd) -{ - struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - - if (!dev) - return -EINVAL; - - mutex_lock(&sl->master->bus_mutex); - - if (w1_reset_select_slave(sl) == 0) { - w1_write_8(sl->master, cmd); - w1_write_8(sl->master, addr); - } - - mutex_unlock(&sl->master->bus_mutex); - return 0; -} - -int w1_ds2760_store_eeprom(struct device *dev, int addr) -{ - return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_COPY_DATA); -} -EXPORT_SYMBOL(w1_ds2760_store_eeprom); - -int w1_ds2760_recall_eeprom(struct device *dev, int addr) -{ - return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA); -} -EXPORT_SYMBOL(w1_ds2760_recall_eeprom); - -static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - return w1_ds2760_read(dev, buf, off, count); -} - -static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE); - -static struct bin_attribute *w1_ds2760_bin_attrs[] = { - &bin_attr_w1_slave, - NULL, -}; - -static const struct attribute_group w1_ds2760_group = { - .bin_attrs = w1_ds2760_bin_attrs, -}; - -static const struct attribute_group *w1_ds2760_groups[] = { - &w1_ds2760_group, - NULL, -}; - -static int w1_ds2760_add_slave(struct w1_slave *sl) -{ - int ret; - struct platform_device *pdev; - - pdev = platform_device_alloc("ds2760-battery", PLATFORM_DEVID_AUTO); - if (!pdev) - return -ENOMEM; - pdev->dev.parent = &sl->dev; - - ret = platform_device_add(pdev); - if (ret) - goto pdev_add_failed; - - dev_set_drvdata(&sl->dev, pdev); - - return 0; - -pdev_add_failed: - platform_device_put(pdev); - - return ret; -} - -static void w1_ds2760_remove_slave(struct w1_slave *sl) -{ - struct platform_device *pdev = dev_get_drvdata(&sl->dev); - - platform_device_unregister(pdev); -} - -static struct w1_family_ops w1_ds2760_fops = { - .add_slave = w1_ds2760_add_slave, - .remove_slave = w1_ds2760_remove_slave, - .groups = w1_ds2760_groups, -}; - -static struct w1_family w1_ds2760_family = { - .fid = W1_FAMILY_DS2760, - .fops = &w1_ds2760_fops, -}; -module_w1_family(w1_ds2760_family); - -MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>"); -MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2760)); diff --git a/drivers/w1/slaves/w1_ds2760.h b/drivers/w1/slaves/w1_ds2760.h deleted file mode 100644 index 24168c94eeae..000000000000 --- a/drivers/w1/slaves/w1_ds2760.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 1-Wire implementation for the ds2760 chip - * - * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> - * - * Use consistent with the GNU GPL is permitted, - * provided that this copyright notice is - * preserved in its entirety in all copies and derived works. - * - */ - -#ifndef __w1_ds2760_h__ -#define __w1_ds2760_h__ - -/* Known commands to the DS2760 chip */ -#define W1_DS2760_SWAP 0xAA -#define W1_DS2760_READ_DATA 0x69 -#define W1_DS2760_WRITE_DATA 0x6C -#define W1_DS2760_COPY_DATA 0x48 -#define W1_DS2760_RECALL_DATA 0xB8 -#define W1_DS2760_LOCK 0x6A - -/* Number of valid register addresses */ -#define DS2760_DATA_SIZE 0x40 - -#define DS2760_PROTECTION_REG 0x00 - -#define DS2760_STATUS_REG 0x01 -#define DS2760_STATUS_IE (1 << 2) -#define DS2760_STATUS_SWEN (1 << 3) -#define DS2760_STATUS_RNAOP (1 << 4) -#define DS2760_STATUS_PMOD (1 << 5) - -#define DS2760_EEPROM_REG 0x07 -#define DS2760_SPECIAL_FEATURE_REG 0x08 -#define DS2760_VOLTAGE_MSB 0x0c -#define DS2760_VOLTAGE_LSB 0x0d -#define DS2760_CURRENT_MSB 0x0e -#define DS2760_CURRENT_LSB 0x0f -#define DS2760_CURRENT_ACCUM_MSB 0x10 -#define DS2760_CURRENT_ACCUM_LSB 0x11 -#define DS2760_TEMP_MSB 0x18 -#define DS2760_TEMP_LSB 0x19 -#define DS2760_EEPROM_BLOCK0 0x20 -#define DS2760_ACTIVE_FULL 0x20 -#define DS2760_EEPROM_BLOCK1 0x30 -#define DS2760_STATUS_WRITE_REG 0x31 -#define DS2760_RATED_CAPACITY 0x32 -#define DS2760_CURRENT_OFFSET_BIAS 0x33 -#define DS2760_ACTIVE_EMPTY 0x3b - -extern int w1_ds2760_read(struct device *dev, char *buf, int addr, - size_t count); -extern int w1_ds2760_write(struct device *dev, char *buf, int addr, - size_t count); -extern int w1_ds2760_store_eeprom(struct device *dev, int addr); -extern int w1_ds2760_recall_eeprom(struct device *dev, int addr); - -#endif /* !__w1_ds2760_h__ */ diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index caef0e0fd817..890c038c25f8 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -26,6 +26,7 @@ #include <linux/kthread.h> #include <linux/freezer.h> #include <linux/hwmon.h> +#include <linux/of.h> #include <linux/atomic.h> @@ -686,6 +687,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) sl->dev.bus = &w1_bus_type; sl->dev.release = &w1_slave_release; sl->dev.groups = w1_slave_groups; + sl->dev.of_node = of_find_matching_node(sl->master->dev.of_node, + sl->family->of_match_table); dev_set_name(&sl->dev, "%02x-%012llx", (unsigned int) sl->reg_num.family, diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c index 2f3b049ea301..e268add43010 100644 --- a/drivers/watchdog/kempld_wdt.c +++ b/drivers/watchdog/kempld_wdt.c @@ -146,12 +146,7 @@ static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data, u32 remainder; u8 stage_cfg; -#if GCC_VERSION < 40400 - /* work around a bug compiling do_div() */ - prescaler = READ_ONCE(kempld_prescaler[PRESCALER_21]); -#else prescaler = kempld_prescaler[PRESCALER_21]; -#endif if (!stage) return -EINVAL; diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index c866a62f766d..57390c7666e5 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -479,18 +479,25 @@ static const struct vm_operations_struct gntdev_vmops = { /* ------------------------------------------------------------------ */ +static bool in_range(struct gntdev_grant_map *map, + unsigned long start, unsigned long end) +{ + if (!map->vma) + return false; + if (map->vma->vm_start >= end) + return false; + if (map->vma->vm_end <= start) + return false; + + return true; +} + static void unmap_if_in_range(struct gntdev_grant_map *map, unsigned long start, unsigned long end) { unsigned long mstart, mend; int err; - if (!map->vma) - return; - if (map->vma->vm_start >= end) - return; - if (map->vma->vm_end <= start) - return; mstart = max(start, map->vma->vm_start); mend = min(end, map->vma->vm_end); pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n", @@ -503,21 +510,40 @@ static void unmap_if_in_range(struct gntdev_grant_map *map, WARN_ON(err); } -static void mn_invl_range_start(struct mmu_notifier *mn, +static int mn_invl_range_start(struct mmu_notifier *mn, struct mm_struct *mm, - unsigned long start, unsigned long end) + unsigned long start, unsigned long end, + bool blockable) { struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn); struct gntdev_grant_map *map; + int ret = 0; + + /* TODO do we really need a mutex here? */ + if (blockable) + mutex_lock(&priv->lock); + else if (!mutex_trylock(&priv->lock)) + return -EAGAIN; - mutex_lock(&priv->lock); list_for_each_entry(map, &priv->maps, next) { + if (in_range(map, start, end)) { + ret = -EAGAIN; + goto out_unlock; + } unmap_if_in_range(map, start, end); } list_for_each_entry(map, &priv->freeable_maps, next) { + if (in_range(map, start, end)) { + ret = -EAGAIN; + goto out_unlock; + } unmap_if_in_range(map, start, end); } + +out_unlock: mutex_unlock(&priv->lock); + + return ret; } static void mn_release(struct mmu_notifier *mn, diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c index 262835ace35d..b8bf61abb65b 100644 --- a/drivers/xen/mcelog.c +++ b/drivers/xen/mcelog.c @@ -288,7 +288,6 @@ static int mc_queue_handle(uint32_t flags) int ret = 0; mc_op.cmd = XEN_MC_fetch; - mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; set_xen_guest_handle(mc_op.u.mc_fetch.data, &g_mi); do { mc_op.u.mc_fetch.flags = flags; @@ -358,7 +357,6 @@ static int bind_virq_for_mce(void) /* Fetch physical CPU Numbers */ mc_op.cmd = XEN_MC_physcpuinfo; - mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo); ret = HYPERVISOR_mca(&mc_op); if (ret) { diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index b29f4e40851f..fbb9137c7d02 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -362,6 +362,12 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv) default: return AE_OK; } + if (invalid_phys_cpuid(acpi_get_phys_id(handle, + acpi_type == ACPI_TYPE_DEVICE, + acpi_id))) { + pr_debug("CPU with ACPI ID %u is unavailable\n", acpi_id); + return AE_OK; + } /* There are more ACPI Processor objects than in x2APIC or MADT. * This can happen with incorrect ACPI SSDT declerations. */ if (acpi_id >= nr_acpi_bits) { |