diff options
Diffstat (limited to 'drivers/bluetooth/hci_qca.c')
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 135 |
1 files changed, 55 insertions, 80 deletions
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index e3164c200eac..c591a8ba9d93 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -130,8 +130,6 @@ enum qca_speed_type { */ struct qca_vreg { const char *name; - unsigned int min_uV; - unsigned int max_uV; unsigned int load_uA; }; @@ -146,8 +144,8 @@ struct qca_vreg_data { */ struct qca_power { struct device *dev; - const struct qca_vreg_data *vreg_data; struct regulator_bulk_data *vreg_bulk; + int num_vregs; bool vregs_on; }; @@ -162,7 +160,8 @@ struct qca_serdev { const char *firmware_name; }; -static int qca_power_setup(struct hci_uart *hu, bool on); +static int qca_regulator_enable(struct qca_serdev *qcadev); +static void qca_regulator_disable(struct qca_serdev *qcadev); static void qca_power_shutdown(struct hci_uart *hu); static int qca_power_off(struct hci_dev *hdev); @@ -518,7 +517,7 @@ static int qca_open(struct hci_uart *hu) } else { hu->init_speed = qcadev->init_speed; hu->oper_speed = qcadev->oper_speed; - ret = qca_power_setup(hu, true); + ret = qca_regulator_enable(qcadev); if (ret) { destroy_workqueue(qca->workqueue); kfree_skb(qca->rx_skb); @@ -1188,7 +1187,7 @@ static int qca_wcn3990_init(struct hci_uart *hu) qcadev = serdev_device_get_drvdata(hu->serdev); if (!qcadev->bt_power->vregs_on) { serdev_device_close(hu->serdev); - ret = qca_power_setup(hu, true); + ret = qca_regulator_enable(qcadev); if (ret) return ret; @@ -1332,10 +1331,10 @@ static const struct hci_uart_proto qca_proto = { static const struct qca_vreg_data qca_soc_data_wcn3990 = { .soc_type = QCA_WCN3990, .vregs = (struct qca_vreg []) { - { "vddio", 1800000, 1900000, 15000 }, - { "vddxo", 1800000, 1900000, 80000 }, - { "vddrf", 1300000, 1350000, 300000 }, - { "vddch0", 3300000, 3400000, 450000 }, + { "vddio", 15000 }, + { "vddxo", 80000 }, + { "vddrf", 300000 }, + { "vddch0", 450000 }, }, .num_vregs = 4, }; @@ -1343,19 +1342,22 @@ static const struct qca_vreg_data qca_soc_data_wcn3990 = { static const struct qca_vreg_data qca_soc_data_wcn3998 = { .soc_type = QCA_WCN3998, .vregs = (struct qca_vreg []) { - { "vddio", 1800000, 1900000, 10000 }, - { "vddxo", 1800000, 1900000, 80000 }, - { "vddrf", 1300000, 1352000, 300000 }, - { "vddch0", 3300000, 3300000, 450000 }, + { "vddio", 10000 }, + { "vddxo", 80000 }, + { "vddrf", 300000 }, + { "vddch0", 450000 }, }, .num_vregs = 4, }; static void qca_power_shutdown(struct hci_uart *hu) { + struct qca_serdev *qcadev; struct qca_data *qca = hu->priv; unsigned long flags; + qcadev = serdev_device_get_drvdata(hu->serdev); + /* From this point we go into power off state. But serial port is * still open, stop queueing the IBS data and flush all the buffered * data in skb's. @@ -1367,7 +1369,7 @@ static void qca_power_shutdown(struct hci_uart *hu) host_set_baudrate(hu, 2400); qca_send_power_pulse(hu, false); - qca_power_setup(hu, false); + qca_regulator_disable(qcadev); } static int qca_power_off(struct hci_dev *hdev) @@ -1383,97 +1385,71 @@ static int qca_power_off(struct hci_dev *hdev) return 0; } -static int qca_enable_regulator(struct qca_vreg vregs, - struct regulator *regulator) +static int qca_regulator_enable(struct qca_serdev *qcadev) { + struct qca_power *power = qcadev->bt_power; int ret; - ret = regulator_set_voltage(regulator, vregs.min_uV, - vregs.max_uV); - if (ret) - return ret; + /* Already enabled */ + if (power->vregs_on) + return 0; - if (vregs.load_uA) - ret = regulator_set_load(regulator, - vregs.load_uA); + BT_DBG("enabling %d regulators)", power->num_vregs); + ret = regulator_bulk_enable(power->num_vregs, power->vreg_bulk); if (ret) return ret; - return regulator_enable(regulator); - -} - -static void qca_disable_regulator(struct qca_vreg vregs, - struct regulator *regulator) -{ - regulator_disable(regulator); - regulator_set_voltage(regulator, 0, vregs.max_uV); - if (vregs.load_uA) - regulator_set_load(regulator, 0); + power->vregs_on = true; + return 0; } -static int qca_power_setup(struct hci_uart *hu, bool on) +static void qca_regulator_disable(struct qca_serdev *qcadev) { - struct qca_vreg *vregs; - struct regulator_bulk_data *vreg_bulk; - struct qca_serdev *qcadev; - int i, num_vregs, ret = 0; + struct qca_power *power; - qcadev = serdev_device_get_drvdata(hu->serdev); - if (!qcadev || !qcadev->bt_power || !qcadev->bt_power->vreg_data || - !qcadev->bt_power->vreg_bulk) - return -EINVAL; - - vregs = qcadev->bt_power->vreg_data->vregs; - vreg_bulk = qcadev->bt_power->vreg_bulk; - num_vregs = qcadev->bt_power->vreg_data->num_vregs; - BT_DBG("on: %d", on); - if (on && !qcadev->bt_power->vregs_on) { - for (i = 0; i < num_vregs; i++) { - ret = qca_enable_regulator(vregs[i], - vreg_bulk[i].consumer); - if (ret) - break; - } + if (!qcadev) + return; - if (ret) { - BT_ERR("failed to enable regulator:%s", vregs[i].name); - /* turn off regulators which are enabled */ - for (i = i - 1; i >= 0; i--) - qca_disable_regulator(vregs[i], - vreg_bulk[i].consumer); - } else { - qcadev->bt_power->vregs_on = true; - } - } else if (!on && qcadev->bt_power->vregs_on) { - /* turn off regulator in reverse order */ - i = qcadev->bt_power->vreg_data->num_vregs - 1; - for ( ; i >= 0; i--) - qca_disable_regulator(vregs[i], vreg_bulk[i].consumer); + power = qcadev->bt_power; - qcadev->bt_power->vregs_on = false; - } + /* Already disabled? */ + if (!power->vregs_on) + return; - return ret; + regulator_bulk_disable(power->num_vregs, power->vreg_bulk); + power->vregs_on = false; } static int qca_init_regulators(struct qca_power *qca, const struct qca_vreg *vregs, size_t num_vregs) { + struct regulator_bulk_data *bulk; + int ret; int i; - qca->vreg_bulk = devm_kcalloc(qca->dev, num_vregs, - sizeof(struct regulator_bulk_data), - GFP_KERNEL); - if (!qca->vreg_bulk) + bulk = devm_kcalloc(qca->dev, num_vregs, sizeof(*bulk), GFP_KERNEL); + if (!bulk) return -ENOMEM; for (i = 0; i < num_vregs; i++) - qca->vreg_bulk[i].supply = vregs[i].name; + bulk[i].supply = vregs[i].name; + + ret = devm_regulator_bulk_get(qca->dev, num_vregs, bulk); + if (ret < 0) + return ret; - return devm_regulator_bulk_get(qca->dev, num_vregs, qca->vreg_bulk); + for (i = 0; i < num_vregs; i++) { + ret = regulator_set_load(bulk[i].consumer, vregs[i].load_uA); + if (ret) + return ret; + } + + qca->vreg_bulk = bulk; + qca->num_vregs = num_vregs; + + return 0; } static int qca_serdev_probe(struct serdev_device *serdev) @@ -1500,7 +1476,6 @@ static int qca_serdev_probe(struct serdev_device *serdev) return -ENOMEM; qcadev->bt_power->dev = &serdev->dev; - qcadev->bt_power->vreg_data = data; err = qca_init_regulators(qcadev->bt_power, data->vregs, data->num_vregs); if (err) { |