DSM_SET_RESET_METHOD = 3,
 };
 
+#define BTINTEL_BT_DOMAIN              0x12
+#define BTINTEL_SAR_LEGACY             0
+#define BTINTEL_SAR_INC_PWR            1
+#define BTINTEL_SAR_INC_PWR_SUPPORTED  0
+
 #define CMD_WRITE_BOOT_PARAMS  0xfc0e
 struct cmd_write_boot_params {
        __le32 boot_addr;
        return 0;
 }
 
+#ifdef CONFIG_ACPI
+static acpi_status btintel_evaluate_acpi_method(struct hci_dev *hdev,
+                                               acpi_string method,
+                                               union acpi_object **ptr,
+                                               u8 pkg_size)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *p;
+       acpi_status status;
+       acpi_handle handle;
+
+       handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
+       if (!handle) {
+               bt_dev_dbg(hdev, "ACPI-BT: No ACPI support for Bluetooth device");
+               return AE_NOT_EXIST;
+       }
+
+       status = acpi_evaluate_object(handle, method, NULL, &buffer);
+
+       if (ACPI_FAILURE(status)) {
+               bt_dev_dbg(hdev, "ACPI-BT: ACPI Failure: %s method: %s",
+                          acpi_format_exception(status), method);
+               return status;
+       }
+
+       p = buffer.pointer;
+
+       if (p->type != ACPI_TYPE_PACKAGE || p->package.count < pkg_size) {
+               bt_dev_warn(hdev, "ACPI-BT: Invalid object type: %d or package count: %d",
+                           p->type, p->package.count);
+               kfree(buffer.pointer);
+               return AE_ERROR;
+       }
+
+       *ptr = buffer.pointer;
+       return 0;
+}
+
+static union acpi_object *btintel_acpi_get_bt_pkg(union acpi_object *buffer)
+{
+       union acpi_object *domain, *bt_pkg;
+       int i;
+
+       for (i = 1; i < buffer->package.count; i++) {
+               bt_pkg = &buffer->package.elements[i];
+               domain = &bt_pkg->package.elements[0];
+               if (domain->type == ACPI_TYPE_INTEGER &&
+                   domain->integer.value == BTINTEL_BT_DOMAIN)
+                       return bt_pkg;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
+static int btintel_send_sar_ddc(struct hci_dev *hdev, struct btintel_cp_ddc_write *data, u8 len)
+{
+       struct sk_buff *skb;
+
+       skb = __hci_cmd_sync(hdev, 0xfc8b, len, data, HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_warn(hdev, "Failed to send sar ddc id:0x%4.4x (%ld)",
+                           le16_to_cpu(data->id), PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+       kfree_skb(skb);
+       return 0;
+}
+
+static int btintel_send_edr(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd,
+                           int id, struct btintel_sar_inc_pwr *sar)
+{
+       cmd->len = 5;
+       cmd->id = cpu_to_le16(id);
+       cmd->data[0] = sar->br >> 3;
+       cmd->data[1] = sar->edr2 >> 3;
+       cmd->data[2] = sar->edr3 >> 3;
+       return btintel_send_sar_ddc(hdev, cmd, 6);
+}
+
+static int btintel_send_le(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd,
+                          int id, struct btintel_sar_inc_pwr *sar)
+{
+       cmd->len = 3;
+       cmd->id = cpu_to_le16(id);
+       cmd->data[0] = min3(sar->le, sar->le_lr, sar->le_2mhz) >> 3;
+       return btintel_send_sar_ddc(hdev, cmd, 4);
+}
+
+static int btintel_send_br(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd,
+                          int id, struct btintel_sar_inc_pwr *sar)
+{
+       cmd->len = 3;
+       cmd->id = cpu_to_le16(id);
+       cmd->data[0] = sar->br >> 3;
+       return btintel_send_sar_ddc(hdev, cmd, 4);
+}
+
+static int btintel_send_br_mutual(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd,
+                                 int id, struct btintel_sar_inc_pwr *sar)
+{
+       cmd->len = 3;
+       cmd->id = cpu_to_le16(id);
+       cmd->data[0] = sar->br;
+       return btintel_send_sar_ddc(hdev, cmd, 4);
+}
+
+static int btintel_send_edr2(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd,
+                            int id, struct btintel_sar_inc_pwr *sar)
+{
+       cmd->len = 3;
+       cmd->id = cpu_to_le16(id);
+       cmd->data[0] = sar->edr2;
+       return btintel_send_sar_ddc(hdev, cmd, 4);
+}
+
+static int btintel_send_edr3(struct hci_dev *hdev, struct btintel_cp_ddc_write *cmd,
+                            int id, struct btintel_sar_inc_pwr *sar)
+{
+       cmd->len = 3;
+       cmd->id = cpu_to_le16(id);
+       cmd->data[0] = sar->edr3;
+       return btintel_send_sar_ddc(hdev, cmd, 4);
+}
+
+static int btintel_set_legacy_sar(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar)
+{
+       struct btintel_cp_ddc_write *cmd;
+       u8 buffer[64];
+       int ret;
+
+       cmd = (void *)buffer;
+       ret = btintel_send_br(hdev, cmd, 0x0131, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_br(hdev, cmd, 0x0132, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_le(hdev, cmd, 0x0133, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_edr(hdev, cmd, 0x0137, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_edr(hdev, cmd, 0x0138, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_edr(hdev, cmd, 0x013b, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_edr(hdev, cmd, 0x013c, sar);
+
+       return ret;
+}
+
+static int btintel_set_mutual_sar(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar)
+{
+       struct btintel_cp_ddc_write *cmd;
+       struct sk_buff *skb;
+       u8 buffer[64];
+       bool enable;
+       int ret;
+
+       cmd = (void *)buffer;
+
+       cmd->len = 3;
+       cmd->id = cpu_to_le16(0x019e);
+
+       if (sar->revision == BTINTEL_SAR_INC_PWR &&
+           sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED)
+               cmd->data[0] = 0x01;
+       else
+               cmd->data[0] = 0x00;
+
+       ret = btintel_send_sar_ddc(hdev, cmd, 4);
+       if (ret)
+               return ret;
+
+       if (sar->revision == BTINTEL_SAR_INC_PWR &&
+           sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED) {
+               cmd->len = 3;
+               cmd->id = cpu_to_le16(0x019f);
+               cmd->data[0] = sar->sar_2400_chain_a;
+
+               ret = btintel_send_sar_ddc(hdev, cmd, 4);
+               if (ret)
+                       return ret;
+       }
+
+       ret = btintel_send_br_mutual(hdev, cmd, 0x01a0, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_edr2(hdev, cmd, 0x01a1, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_edr3(hdev, cmd, 0x01a2, sar);
+       if (ret)
+               return ret;
+
+       ret = btintel_send_le(hdev, cmd, 0x01a3, sar);
+       if (ret)
+               return ret;
+
+       enable = true;
+       skb = __hci_cmd_sync(hdev, 0xfe25, 1, &enable, HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_warn(hdev, "Failed to send Intel SAR Enable (%ld)", PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static int btintel_sar_send_to_device(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar,
+                                     struct intel_version_tlv *ver)
+{
+       u16 cnvi, cnvr;
+       int ret;
+
+       cnvi = ver->cnvi_top & 0xfff;
+       cnvr = ver->cnvr_top & 0xfff;
+
+       if (cnvi < BTINTEL_CNVI_BLAZARI && cnvr < BTINTEL_CNVR_FMP2) {
+               bt_dev_info(hdev, "Applying legacy Bluetooth SAR");
+               ret = btintel_set_legacy_sar(hdev, sar);
+       } else if (cnvi == BTINTEL_CNVI_GAP || cnvr == BTINTEL_CNVR_FMP2) {
+               bt_dev_info(hdev, "Applying mutual Bluetooth SAR");
+               ret = btintel_set_mutual_sar(hdev, sar);
+       } else {
+               ret = -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
+static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *ver)
+{
+       union acpi_object *bt_pkg, *buffer = NULL;
+       struct btintel_sar_inc_pwr sar;
+       acpi_status status;
+       u8 revision;
+       int ret;
+
+       status = btintel_evaluate_acpi_method(hdev, "BRDS", &buffer, 2);
+       if (ACPI_FAILURE(status))
+               return -ENOENT;
+
+       bt_pkg = btintel_acpi_get_bt_pkg(buffer);
+
+       if (IS_ERR(bt_pkg)) {
+               ret = PTR_ERR(bt_pkg);
+               goto error;
+       }
+
+       if (!bt_pkg->package.count) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       revision = buffer->package.elements[0].integer.value;
+
+       if (revision > BTINTEL_SAR_INC_PWR) {
+               bt_dev_dbg(hdev, "BT_SAR: revision: 0x%2.2x not supported", revision);
+               ret = -EOPNOTSUPP;
+               goto error;
+       }
+
+       memset(&sar, 0, sizeof(sar));
+
+       if (revision == BTINTEL_SAR_LEGACY && bt_pkg->package.count == 8) {
+               sar.revision = revision;
+               sar.bt_sar_bios = bt_pkg->package.elements[1].integer.value;
+               sar.br = bt_pkg->package.elements[2].integer.value;
+               sar.edr2 = bt_pkg->package.elements[3].integer.value;
+               sar.edr3 = bt_pkg->package.elements[4].integer.value;
+               sar.le = bt_pkg->package.elements[5].integer.value;
+               sar.le_2mhz = bt_pkg->package.elements[6].integer.value;
+               sar.le_lr  = bt_pkg->package.elements[7].integer.value;
+
+       } else if (revision == BTINTEL_SAR_INC_PWR && bt_pkg->package.count == 10) {
+               sar.revision = revision;
+               sar.bt_sar_bios = bt_pkg->package.elements[1].integer.value;
+               sar.inc_power_mode = bt_pkg->package.elements[2].integer.value;
+               sar.sar_2400_chain_a = bt_pkg->package.elements[3].integer.value;
+               sar.br = bt_pkg->package.elements[4].integer.value;
+               sar.edr2 = bt_pkg->package.elements[5].integer.value;
+               sar.edr3 = bt_pkg->package.elements[6].integer.value;
+               sar.le = bt_pkg->package.elements[7].integer.value;
+               sar.le_2mhz = bt_pkg->package.elements[8].integer.value;
+               sar.le_lr  = bt_pkg->package.elements[9].integer.value;
+       } else {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Apply only if it is enabled in BIOS */
+       if (sar.bt_sar_bios != 1) {
+               bt_dev_dbg(hdev, "Bluetooth SAR is not enabled");
+               ret = -EOPNOTSUPP;
+               goto error;
+       }
+
+       ret = btintel_sar_send_to_device(hdev, &sar, ver);
+error:
+       kfree(buffer);
+       return ret;
+}
+#endif /* CONFIG_ACPI */
+
+static int btintel_set_specific_absorption_rate(struct hci_dev *hdev,
+                                               struct intel_version_tlv *ver)
+{
+#ifdef CONFIG_ACPI
+       return btintel_acpi_set_sar(hdev, ver);
+#endif
+       return 0;
+}
+
 int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
                                 struct intel_version_tlv *ver)
 {
 
        hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
 
+       /* Send sar values to controller */
+       btintel_set_specific_absorption_rate(hdev, ver);
+
        /* Set PPAG feature */
        btintel_set_ppag(hdev, ver);