Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // arizona-micsupp.c  --  Microphone supply for Arizona devices
0004 //
0005 // Copyright 2012 Wolfson Microelectronics PLC.
0006 //
0007 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
0008 
0009 #include <linux/module.h>
0010 #include <linux/moduleparam.h>
0011 #include <linux/init.h>
0012 #include <linux/bitops.h>
0013 #include <linux/err.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regulator/driver.h>
0017 #include <linux/regulator/machine.h>
0018 #include <linux/regulator/of_regulator.h>
0019 #include <linux/slab.h>
0020 #include <linux/workqueue.h>
0021 #include <sound/soc.h>
0022 
0023 #include <linux/mfd/arizona/core.h>
0024 #include <linux/mfd/arizona/pdata.h>
0025 #include <linux/mfd/arizona/registers.h>
0026 
0027 #include <linux/mfd/madera/core.h>
0028 #include <linux/mfd/madera/pdata.h>
0029 #include <linux/mfd/madera/registers.h>
0030 
0031 #include <linux/regulator/arizona-micsupp.h>
0032 
0033 struct arizona_micsupp {
0034     struct regulator_dev *regulator;
0035     struct regmap *regmap;
0036     struct snd_soc_dapm_context **dapm;
0037     unsigned int enable_reg;
0038     struct device *dev;
0039 
0040     struct regulator_consumer_supply supply;
0041     struct regulator_init_data init_data;
0042 
0043     struct work_struct check_cp_work;
0044 };
0045 
0046 static void arizona_micsupp_check_cp(struct work_struct *work)
0047 {
0048     struct arizona_micsupp *micsupp =
0049         container_of(work, struct arizona_micsupp, check_cp_work);
0050     struct snd_soc_dapm_context *dapm = *micsupp->dapm;
0051     struct snd_soc_component *component;
0052     unsigned int val;
0053     int ret;
0054 
0055     ret = regmap_read(micsupp->regmap, micsupp->enable_reg, &val);
0056     if (ret != 0) {
0057         dev_err(micsupp->dev,
0058             "Failed to read CP state: %d\n", ret);
0059         return;
0060     }
0061 
0062     if (dapm) {
0063         component = snd_soc_dapm_to_component(dapm);
0064 
0065         if ((val & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
0066             ARIZONA_CPMIC_ENA)
0067             snd_soc_component_force_enable_pin(component,
0068                                "MICSUPP");
0069         else
0070             snd_soc_component_disable_pin(component, "MICSUPP");
0071 
0072         snd_soc_dapm_sync(dapm);
0073     }
0074 }
0075 
0076 static int arizona_micsupp_enable(struct regulator_dev *rdev)
0077 {
0078     struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
0079     int ret;
0080 
0081     ret = regulator_enable_regmap(rdev);
0082 
0083     if (ret == 0)
0084         schedule_work(&micsupp->check_cp_work);
0085 
0086     return ret;
0087 }
0088 
0089 static int arizona_micsupp_disable(struct regulator_dev *rdev)
0090 {
0091     struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
0092     int ret;
0093 
0094     ret = regulator_disable_regmap(rdev);
0095     if (ret == 0)
0096         schedule_work(&micsupp->check_cp_work);
0097 
0098     return ret;
0099 }
0100 
0101 static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
0102 {
0103     struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
0104     int ret;
0105 
0106     ret = regulator_set_bypass_regmap(rdev, ena);
0107     if (ret == 0)
0108         schedule_work(&micsupp->check_cp_work);
0109 
0110     return ret;
0111 }
0112 
0113 static const struct regulator_ops arizona_micsupp_ops = {
0114     .enable = arizona_micsupp_enable,
0115     .disable = arizona_micsupp_disable,
0116     .is_enabled = regulator_is_enabled_regmap,
0117 
0118     .list_voltage = regulator_list_voltage_linear_range,
0119     .map_voltage = regulator_map_voltage_linear_range,
0120 
0121     .get_voltage_sel = regulator_get_voltage_sel_regmap,
0122     .set_voltage_sel = regulator_set_voltage_sel_regmap,
0123 
0124     .get_bypass = regulator_get_bypass_regmap,
0125     .set_bypass = arizona_micsupp_set_bypass,
0126 };
0127 
0128 static const struct linear_range arizona_micsupp_ranges[] = {
0129     REGULATOR_LINEAR_RANGE(1700000, 0,    0x1e, 50000),
0130     REGULATOR_LINEAR_RANGE(3300000, 0x1f, 0x1f, 0),
0131 };
0132 
0133 static const struct regulator_desc arizona_micsupp = {
0134     .name = "MICVDD",
0135     .supply_name = "CPVDD",
0136     .type = REGULATOR_VOLTAGE,
0137     .n_voltages = 32,
0138     .ops = &arizona_micsupp_ops,
0139 
0140     .vsel_reg = ARIZONA_LDO2_CONTROL_1,
0141     .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
0142     .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
0143     .enable_mask = ARIZONA_CPMIC_ENA,
0144     .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
0145     .bypass_mask = ARIZONA_CPMIC_BYPASS,
0146 
0147     .linear_ranges = arizona_micsupp_ranges,
0148     .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ranges),
0149 
0150     .enable_time = 3000,
0151 
0152     .owner = THIS_MODULE,
0153 };
0154 
0155 static const struct linear_range arizona_micsupp_ext_ranges[] = {
0156     REGULATOR_LINEAR_RANGE(900000,  0,    0x14, 25000),
0157     REGULATOR_LINEAR_RANGE(1500000, 0x15, 0x27, 100000),
0158 };
0159 
0160 static const struct regulator_desc arizona_micsupp_ext = {
0161     .name = "MICVDD",
0162     .supply_name = "CPVDD",
0163     .type = REGULATOR_VOLTAGE,
0164     .n_voltages = 40,
0165     .ops = &arizona_micsupp_ops,
0166 
0167     .vsel_reg = ARIZONA_LDO2_CONTROL_1,
0168     .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
0169     .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
0170     .enable_mask = ARIZONA_CPMIC_ENA,
0171     .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
0172     .bypass_mask = ARIZONA_CPMIC_BYPASS,
0173 
0174     .linear_ranges = arizona_micsupp_ext_ranges,
0175     .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges),
0176 
0177     .enable_time = 3000,
0178 
0179     .owner = THIS_MODULE,
0180 };
0181 
0182 static const struct regulator_init_data arizona_micsupp_default = {
0183     .constraints = {
0184         .valid_ops_mask = REGULATOR_CHANGE_STATUS |
0185                 REGULATOR_CHANGE_VOLTAGE |
0186                 REGULATOR_CHANGE_BYPASS,
0187         .min_uV = 1700000,
0188         .max_uV = 3300000,
0189     },
0190 
0191     .num_consumer_supplies = 1,
0192 };
0193 
0194 static const struct regulator_init_data arizona_micsupp_ext_default = {
0195     .constraints = {
0196         .valid_ops_mask = REGULATOR_CHANGE_STATUS |
0197                 REGULATOR_CHANGE_VOLTAGE |
0198                 REGULATOR_CHANGE_BYPASS,
0199         .min_uV = 900000,
0200         .max_uV = 3300000,
0201     },
0202 
0203     .num_consumer_supplies = 1,
0204 };
0205 
0206 static const struct regulator_desc madera_micsupp = {
0207     .name = "MICVDD",
0208     .supply_name = "CPVDD1",
0209     .type = REGULATOR_VOLTAGE,
0210     .n_voltages = 40,
0211     .ops = &arizona_micsupp_ops,
0212 
0213     .vsel_reg = MADERA_LDO2_CONTROL_1,
0214     .vsel_mask = MADERA_LDO2_VSEL_MASK,
0215     .enable_reg = MADERA_MIC_CHARGE_PUMP_1,
0216     .enable_mask = MADERA_CPMIC_ENA,
0217     .bypass_reg = MADERA_MIC_CHARGE_PUMP_1,
0218     .bypass_mask = MADERA_CPMIC_BYPASS,
0219 
0220     .linear_ranges = arizona_micsupp_ext_ranges,
0221     .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges),
0222 
0223     .enable_time = 3000,
0224 
0225     .owner = THIS_MODULE,
0226 };
0227 
0228 static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata,
0229                     struct regulator_config *config,
0230                     const struct regulator_desc *desc)
0231 {
0232     struct arizona_micsupp *micsupp = config->driver_data;
0233     struct device_node *np;
0234     struct regulator_init_data *init_data;
0235 
0236     np = of_get_child_by_name(config->dev->of_node, "micvdd");
0237 
0238     if (np) {
0239         config->of_node = np;
0240 
0241         init_data = of_get_regulator_init_data(config->dev, np, desc);
0242 
0243         if (init_data) {
0244             init_data->consumer_supplies = &micsupp->supply;
0245             init_data->num_consumer_supplies = 1;
0246 
0247             pdata->init_data = init_data;
0248         }
0249     }
0250 
0251     return 0;
0252 }
0253 
0254 static int arizona_micsupp_common_init(struct platform_device *pdev,
0255                        struct arizona_micsupp *micsupp,
0256                        const struct regulator_desc *desc,
0257                        struct arizona_micsupp_pdata *pdata)
0258 {
0259     struct regulator_config config = { };
0260     int ret;
0261 
0262     INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
0263 
0264     micsupp->init_data.consumer_supplies = &micsupp->supply;
0265     micsupp->supply.supply = "MICVDD";
0266     micsupp->supply.dev_name = dev_name(micsupp->dev);
0267     micsupp->enable_reg = desc->enable_reg;
0268 
0269     config.dev = micsupp->dev;
0270     config.driver_data = micsupp;
0271     config.regmap = micsupp->regmap;
0272 
0273     if (IS_ENABLED(CONFIG_OF)) {
0274         if (!dev_get_platdata(micsupp->dev)) {
0275             ret = arizona_micsupp_of_get_pdata(pdata, &config,
0276                                desc);
0277             if (ret < 0)
0278                 return ret;
0279         }
0280     }
0281 
0282     if (pdata->init_data)
0283         config.init_data = pdata->init_data;
0284     else
0285         config.init_data = &micsupp->init_data;
0286 
0287     /* Default to regulated mode */
0288     regmap_update_bits(micsupp->regmap, micsupp->enable_reg,
0289                ARIZONA_CPMIC_BYPASS, 0);
0290 
0291     micsupp->regulator = devm_regulator_register(&pdev->dev,
0292                              desc,
0293                              &config);
0294 
0295     of_node_put(config.of_node);
0296 
0297     if (IS_ERR(micsupp->regulator)) {
0298         ret = PTR_ERR(micsupp->regulator);
0299         dev_err(micsupp->dev, "Failed to register mic supply: %d\n",
0300             ret);
0301         return ret;
0302     }
0303 
0304     platform_set_drvdata(pdev, micsupp);
0305 
0306     return 0;
0307 }
0308 
0309 static int arizona_micsupp_probe(struct platform_device *pdev)
0310 {
0311     struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
0312     const struct regulator_desc *desc;
0313     struct arizona_micsupp *micsupp;
0314 
0315     micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
0316     if (!micsupp)
0317         return -ENOMEM;
0318 
0319     micsupp->regmap = arizona->regmap;
0320     micsupp->dapm = &arizona->dapm;
0321     micsupp->dev = arizona->dev;
0322 
0323     /*
0324      * Since the chip usually supplies itself we provide some
0325      * default init_data for it.  This will be overridden with
0326      * platform data if provided.
0327      */
0328     switch (arizona->type) {
0329     case WM5110:
0330     case WM8280:
0331         desc = &arizona_micsupp_ext;
0332         micsupp->init_data = arizona_micsupp_ext_default;
0333         break;
0334     default:
0335         desc = &arizona_micsupp;
0336         micsupp->init_data = arizona_micsupp_default;
0337         break;
0338     }
0339 
0340     return arizona_micsupp_common_init(pdev, micsupp, desc,
0341                        &arizona->pdata.micvdd);
0342 }
0343 
0344 static int madera_micsupp_probe(struct platform_device *pdev)
0345 {
0346     struct madera *madera = dev_get_drvdata(pdev->dev.parent);
0347     struct arizona_micsupp *micsupp;
0348 
0349     micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
0350     if (!micsupp)
0351         return -ENOMEM;
0352 
0353     micsupp->regmap = madera->regmap;
0354     micsupp->dapm = &madera->dapm;
0355     micsupp->dev = madera->dev;
0356     micsupp->init_data = arizona_micsupp_ext_default;
0357 
0358     return arizona_micsupp_common_init(pdev, micsupp, &madera_micsupp,
0359                        &madera->pdata.micvdd);
0360 }
0361 
0362 static struct platform_driver arizona_micsupp_driver = {
0363     .probe = arizona_micsupp_probe,
0364     .driver     = {
0365         .name   = "arizona-micsupp",
0366     },
0367 };
0368 
0369 static struct platform_driver madera_micsupp_driver = {
0370     .probe = madera_micsupp_probe,
0371     .driver     = {
0372         .name   = "madera-micsupp",
0373     },
0374 };
0375 
0376 static struct platform_driver * const arizona_micsupp_drivers[] = {
0377     &arizona_micsupp_driver,
0378     &madera_micsupp_driver,
0379 };
0380 
0381 static int __init arizona_micsupp_init(void)
0382 {
0383     return platform_register_drivers(arizona_micsupp_drivers,
0384                      ARRAY_SIZE(arizona_micsupp_drivers));
0385 }
0386 module_init(arizona_micsupp_init);
0387 
0388 static void __exit arizona_micsupp_exit(void)
0389 {
0390     platform_unregister_drivers(arizona_micsupp_drivers,
0391                     ARRAY_SIZE(arizona_micsupp_drivers));
0392 }
0393 module_exit(arizona_micsupp_exit);
0394 
0395 /* Module information */
0396 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
0397 MODULE_DESCRIPTION("Arizona microphone supply driver");
0398 MODULE_LICENSE("GPL");
0399 MODULE_ALIAS("platform:arizona-micsupp");
0400 MODULE_ALIAS("platform:madera-micsupp");