linux/drivers/regulator/arizona-micsupp.c
Linus Torvalds f0c1bc95a1 == Changes to existing drivers ==
- Rename child driver [axp288_battery => axp288_fuel_gauge]; axp20x
    - Rename child driver [max77693-flash => max77693-led]; max77693
    - Error handling fixes; intel_soc_pmic
    - GPIO tweaking; intel_soc_pmic
    - Remove non-DT code; vexpress-sysreg, tc3589x
    - Remove unused/legacy code; ti_am335x_tscadc, rts5249, rtsx_gops, rtsx_pcr,
                                 rtc-s5m, sec-core, max77693, menelaus,
                                 wm5102-tables
    - Trivial fixups; rtsx_pci, da9150-core, sec-core, max7769, max77693,
                      mc13xxx-core, dln2, hi6421-pmic-core, rk808, twl4030-power,
                      lpc_ich, menelaus, twl6040
    - Update register/address values; rts5227, rts5249
    - DT and/or binding document fixups; arizona, da9150, mt6397, axp20x,
                                         qcom-rpm, qcom-spmi-pmic
    - Couple of trivial core Kconfig fixups
    - Remove use of seq_printf return value; ab8500-debugfs
    - Remove __exit markups; menelaus, tps65010
    - Fix platform-device name collisions; mfd-core
 
  == New drivers/supported devices ==
    - Add support for wm8280/wm8281 into arizona
    - Add support for COMe-cBL6 into kempld-core
    - Add support for rts524a and rts525a into rts5249
    - Add support for ipq8064 into qcom_rpm
    - Add support for extcon into axp20x
    - New MediaTek MT6397 PMIC driver
    - New Maxim MAX77843 PMIC dirver
    - New Intel Quark X1000 I2C-GPIO driver
    - New Skyworks SKY81452 driver
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVLQlhAAoJEFGvii+H/HdhnSYP/i7h+0/uvI32+49XlQWO/zZv
 SIcnNcekSj/8MIIpSOZftY+ejdqyo8NHY0dvNTmxekY65ov/yXA6aJGDd5rr3xyL
 hd9E5e5nwxc4UTV2kJwPBgCIKIjx/idRgOMTEpIa1v4KY8Gn43xc81X4s+BusbCE
 WK8hPdBUePRDmMLrRzhkVHqrfeMSSLN5Z/fhmQehWqahE1asPZ2FOnTC6tFlGxgm
 I55FAMvWey+qv4g28+nQrC9RQMetCL2f/6o53jMEQoaRQdJbbrxMybBnNvpcXwbR
 JECPiV+2R0EqBd3xiT2gbPLAqmMDexIP1Cybh3BBRcFveJeJGqmMCFwMio6kotkA
 IIMlYNcwczufPVWIIqz3U2OtJ5EWzxPgco2aA4a1Ej1nbUC29o829fMahZY0SR8m
 O2zX/MpmYPZCg3mHOFQ4oPwalIM7oKv79NTV25Ks9r+rv+zNaBc8TPCE/Oxkxfj8
 IdJ/vKQaKMmMZA1THO8HMK9qAQV7vZL12XquVzrAgq40RZa+nOUXEk0J0rHI0VaO
 BHNMBv1D3iNQfR7cWAappDavhoZcFtIY/Z9x7OsLYm/W8+CxhdAafMNH0AJPlfts
 NR7RoNtStumXdq6QzDdA27Mp1sXkHz/kgGMVE4t9mdLVmD9C0MqVi8VPFUN+sST0
 vAKAhQ/cnXCKVxe6I9/3
 =QPNn
 -----END PGP SIGNATURE-----

Merge tag 'mfd-for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd

Pull MFD updates from Lee Jones:
 "Changes to existing drivers:

   - Rename child driver [axp288_battery => axp288_fuel_gauge]; axp20x
   - Rename child driver [max77693-flash => max77693-led]; max77693
   - Error handling fixes; intel_soc_pmic
   - GPIO tweaking; intel_soc_pmic
   - Remove non-DT code; vexpress-sysreg, tc3589x
   - Remove unused/legacy code; ti_am335x_tscadc, rts5249, rtsx_gops, rtsx_pcr,
                                rtc-s5m, sec-core, max77693, menelaus,
                                wm5102-tables
   - Trivial fixups; rtsx_pci, da9150-core, sec-core, max7769, max77693,
                     mc13xxx-core, dln2, hi6421-pmic-core, rk808, twl4030-power,
                     lpc_ich, menelaus, twl6040
   - Update register/address values; rts5227, rts5249
   - DT and/or binding document fixups; arizona, da9150, mt6397, axp20x,
                                        qcom-rpm, qcom-spmi-pmic
   - Couple of trivial core Kconfig fixups
   - Remove use of seq_printf return value; ab8500-debugfs
   - Remove __exit markups; menelaus, tps65010
   - Fix platform-device name collisions; mfd-core

  New drivers/supported devices:

   - Add support for wm8280/wm8281 into arizona
   - Add support for COMe-cBL6 into kempld-core
   - Add support for rts524a and rts525a into rts5249
   - Add support for ipq8064 into qcom_rpm
   - Add support for extcon into axp20x
   - New MediaTek MT6397 PMIC driver
   - New Maxim MAX77843 PMIC dirver
   - New Intel Quark X1000 I2C-GPIO driver
   - New Skyworks SKY81452 driver"

* tag 'mfd-for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (76 commits)
  mfd: sec: Fix RTC alarm interrupt number on S2MPS11
  mfd: wm5102: Remove registers for output 3R from readable list
  mfd: tps65010: Remove incorrect __exit markups
  mfd: devicetree: bindings: Add Qualcomm RPM regulator subnodes
  mfd: axp20x: Add support for extcon cell
  mfd: lpc_ich: Sort IDs
  mfd: twl6040: Remove wrong and unneeded "platform:twl6040" modalias
  mfd: qcom-spmi-pmic: Add specific compatible strings for Qualcomm's SPMI PMIC's
  mfd: axp20x: Fix duplicate const for model names
  mfd: menelaus: Use macro for magic number
  mfd: menelaus: Drop support for SW controller VCORE
  mfd: menelaus: Delete omap_has_menelaus
  mfd: arizona: Correct type of gpio_defaults
  mfd: lpc_ich: Sort IDs
  mfd: Fix a typo in Kconfig
  mfd: qcom_rpm: Add support for IPQ8064
  mfd: devicetree: qcom_rpm: Document IPQ8064 resources
  mfd: core: Fix platform-device name collisions
  mfd: intel_quark_i2c_gpio: Don't crash if !DMI
  dt-bindings: Add vendor-prefix for X-Powers
  ...
2015-04-14 17:29:55 -07:00

316 lines
7.9 KiB
C

/*
* arizona-micsupp.c -- Microphone supply for Arizona devices
*
* Copyright 2012 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <sound/soc.h>
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
struct arizona_micsupp {
struct regulator_dev *regulator;
struct arizona *arizona;
struct regulator_consumer_supply supply;
struct regulator_init_data init_data;
struct work_struct check_cp_work;
};
static void arizona_micsupp_check_cp(struct work_struct *work)
{
struct arizona_micsupp *micsupp =
container_of(work, struct arizona_micsupp, check_cp_work);
struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
struct arizona *arizona = micsupp->arizona;
struct regmap *regmap = arizona->regmap;
unsigned int reg;
int ret;
ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, &reg);
if (ret != 0) {
dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
return;
}
if (dapm) {
if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
ARIZONA_CPMIC_ENA)
snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
else
snd_soc_dapm_disable_pin(dapm, "MICSUPP");
snd_soc_dapm_sync(dapm);
}
}
static int arizona_micsupp_enable(struct regulator_dev *rdev)
{
struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
int ret;
ret = regulator_enable_regmap(rdev);
if (ret == 0)
schedule_work(&micsupp->check_cp_work);
return ret;
}
static int arizona_micsupp_disable(struct regulator_dev *rdev)
{
struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
int ret;
ret = regulator_disable_regmap(rdev);
if (ret == 0)
schedule_work(&micsupp->check_cp_work);
return ret;
}
static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
{
struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
int ret;
ret = regulator_set_bypass_regmap(rdev, ena);
if (ret == 0)
schedule_work(&micsupp->check_cp_work);
return ret;
}
static struct regulator_ops arizona_micsupp_ops = {
.enable = arizona_micsupp_enable,
.disable = arizona_micsupp_disable,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_bypass = regulator_get_bypass_regmap,
.set_bypass = arizona_micsupp_set_bypass,
};
static const struct regulator_linear_range arizona_micsupp_ranges[] = {
REGULATOR_LINEAR_RANGE(1700000, 0, 0x1e, 50000),
REGULATOR_LINEAR_RANGE(3300000, 0x1f, 0x1f, 0),
};
static const struct regulator_desc arizona_micsupp = {
.name = "MICVDD",
.supply_name = "CPVDD",
.type = REGULATOR_VOLTAGE,
.n_voltages = 32,
.ops = &arizona_micsupp_ops,
.vsel_reg = ARIZONA_LDO2_CONTROL_1,
.vsel_mask = ARIZONA_LDO2_VSEL_MASK,
.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.enable_mask = ARIZONA_CPMIC_ENA,
.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.bypass_mask = ARIZONA_CPMIC_BYPASS,
.linear_ranges = arizona_micsupp_ranges,
.n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ranges),
.enable_time = 3000,
.owner = THIS_MODULE,
};
static const struct regulator_linear_range arizona_micsupp_ext_ranges[] = {
REGULATOR_LINEAR_RANGE(900000, 0, 0x14, 25000),
REGULATOR_LINEAR_RANGE(1500000, 0x15, 0x27, 100000),
};
static const struct regulator_desc arizona_micsupp_ext = {
.name = "MICVDD",
.supply_name = "CPVDD",
.type = REGULATOR_VOLTAGE,
.n_voltages = 40,
.ops = &arizona_micsupp_ops,
.vsel_reg = ARIZONA_LDO2_CONTROL_1,
.vsel_mask = ARIZONA_LDO2_VSEL_MASK,
.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.enable_mask = ARIZONA_CPMIC_ENA,
.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.bypass_mask = ARIZONA_CPMIC_BYPASS,
.linear_ranges = arizona_micsupp_ext_ranges,
.n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges),
.enable_time = 3000,
.owner = THIS_MODULE,
};
static const struct regulator_init_data arizona_micsupp_default = {
.constraints = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_BYPASS,
.min_uV = 1700000,
.max_uV = 3300000,
},
.num_consumer_supplies = 1,
};
static const struct regulator_init_data arizona_micsupp_ext_default = {
.constraints = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_BYPASS,
.min_uV = 900000,
.max_uV = 3300000,
},
.num_consumer_supplies = 1,
};
static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
struct regulator_config *config,
const struct regulator_desc *desc)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_micsupp *micsupp = config->driver_data;
struct device_node *np;
struct regulator_init_data *init_data;
np = of_get_child_by_name(arizona->dev->of_node, "micvdd");
if (np) {
config->of_node = np;
init_data = of_get_regulator_init_data(arizona->dev, np, desc);
if (init_data) {
init_data->consumer_supplies = &micsupp->supply;
init_data->num_consumer_supplies = 1;
pdata->micvdd = init_data;
}
}
return 0;
}
static int arizona_micsupp_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
const struct regulator_desc *desc;
struct regulator_config config = { };
struct arizona_micsupp *micsupp;
int ret;
micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
if (!micsupp)
return -ENOMEM;
micsupp->arizona = arizona;
INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
/*
* Since the chip usually supplies itself we provide some
* default init_data for it. This will be overridden with
* platform data if provided.
*/
switch (arizona->type) {
case WM5110:
case WM8280:
desc = &arizona_micsupp_ext;
micsupp->init_data = arizona_micsupp_ext_default;
break;
default:
desc = &arizona_micsupp;
micsupp->init_data = arizona_micsupp_default;
break;
}
micsupp->init_data.consumer_supplies = &micsupp->supply;
micsupp->supply.supply = "MICVDD";
micsupp->supply.dev_name = dev_name(arizona->dev);
config.dev = arizona->dev;
config.driver_data = micsupp;
config.regmap = arizona->regmap;
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_micsupp_of_get_pdata(arizona, &config,
desc);
if (ret < 0)
return ret;
}
}
if (arizona->pdata.micvdd)
config.init_data = arizona->pdata.micvdd;
else
config.init_data = &micsupp->init_data;
/* Default to regulated mode until the API supports bypass */
regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1,
ARIZONA_CPMIC_BYPASS, 0);
micsupp->regulator = devm_regulator_register(&pdev->dev,
desc,
&config);
of_node_put(config.of_node);
if (IS_ERR(micsupp->regulator)) {
ret = PTR_ERR(micsupp->regulator);
dev_err(arizona->dev, "Failed to register mic supply: %d\n",
ret);
return ret;
}
platform_set_drvdata(pdev, micsupp);
return 0;
}
static struct platform_driver arizona_micsupp_driver = {
.probe = arizona_micsupp_probe,
.driver = {
.name = "arizona-micsupp",
},
};
module_platform_driver(arizona_micsupp_driver);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Arizona microphone supply driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:arizona-micsupp");