1/* 2 * Copyright (c) 2015 MediaTek Inc. 3 * Author: Henry Chen <henryc.chen@mediatek.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15#include <linux/err.h> 16#include <linux/gpio.h> 17#include <linux/i2c.h> 18#include <linux/init.h> 19#include <linux/interrupt.h> 20#include <linux/module.h> 21#include <linux/regmap.h> 22#include <linux/regulator/driver.h> 23#include <linux/regulator/machine.h> 24#include <linux/regulator/of_regulator.h> 25#include <linux/regulator/mt6311.h> 26#include <linux/slab.h> 27#include "mt6311-regulator.h" 28 29static const struct regmap_config mt6311_regmap_config = { 30 .reg_bits = 8, 31 .val_bits = 8, 32 .max_register = MT6311_FQMTR_CON4, 33}; 34 35/* Default limits measured in millivolts and milliamps */ 36#define MT6311_MIN_UV 600000 37#define MT6311_MAX_UV 1393750 38#define MT6311_STEP_UV 6250 39 40static const struct regulator_linear_range buck_volt_range[] = { 41 REGULATOR_LINEAR_RANGE(MT6311_MIN_UV, 0, 0x7f, MT6311_STEP_UV), 42}; 43 44static const struct regulator_ops mt6311_buck_ops = { 45 .list_voltage = regulator_list_voltage_linear_range, 46 .map_voltage = regulator_map_voltage_linear_range, 47 .set_voltage_sel = regulator_set_voltage_sel_regmap, 48 .get_voltage_sel = regulator_get_voltage_sel_regmap, 49 .set_voltage_time_sel = regulator_set_voltage_time_sel, 50 .enable = regulator_enable_regmap, 51 .disable = regulator_disable_regmap, 52 .is_enabled = regulator_is_enabled_regmap, 53}; 54 55static const struct regulator_ops mt6311_ldo_ops = { 56 .enable = regulator_enable_regmap, 57 .disable = regulator_disable_regmap, 58 .is_enabled = regulator_is_enabled_regmap, 59}; 60 61#define MT6311_BUCK(_id) \ 62{\ 63 .name = #_id,\ 64 .ops = &mt6311_buck_ops,\ 65 .of_match = of_match_ptr(#_id),\ 66 .regulators_node = of_match_ptr("regulators"),\ 67 .type = REGULATOR_VOLTAGE,\ 68 .id = MT6311_ID_##_id,\ 69 .n_voltages = (MT6311_MAX_UV - MT6311_MIN_UV) / MT6311_STEP_UV + 1,\ 70 .min_uV = MT6311_MIN_UV,\ 71 .uV_step = MT6311_STEP_UV,\ 72 .owner = THIS_MODULE,\ 73 .linear_ranges = buck_volt_range, \ 74 .n_linear_ranges = ARRAY_SIZE(buck_volt_range), \ 75 .enable_reg = MT6311_VDVFS11_CON9,\ 76 .enable_mask = MT6311_PMIC_VDVFS11_EN_MASK,\ 77 .vsel_reg = MT6311_VDVFS11_CON12,\ 78 .vsel_mask = MT6311_PMIC_VDVFS11_VOSEL_MASK,\ 79} 80 81#define MT6311_LDO(_id) \ 82{\ 83 .name = #_id,\ 84 .ops = &mt6311_ldo_ops,\ 85 .of_match = of_match_ptr(#_id),\ 86 .regulators_node = of_match_ptr("regulators"),\ 87 .type = REGULATOR_VOLTAGE,\ 88 .id = MT6311_ID_##_id,\ 89 .owner = THIS_MODULE,\ 90 .enable_reg = MT6311_LDO_CON3,\ 91 .enable_mask = MT6311_PMIC_RG_VBIASN_EN_MASK,\ 92} 93 94static const struct regulator_desc mt6311_regulators[] = { 95 MT6311_BUCK(VDVFS), 96 MT6311_LDO(VBIASN), 97}; 98 99/* 100 * I2C driver interface functions 101 */ 102static int mt6311_i2c_probe(struct i2c_client *i2c, 103 const struct i2c_device_id *id) 104{ 105 struct regulator_config config = { }; 106 struct regulator_dev *rdev; 107 struct regmap *regmap; 108 int i, ret; 109 unsigned int data; 110 111 regmap = devm_regmap_init_i2c(i2c, &mt6311_regmap_config); 112 if (IS_ERR(regmap)) { 113 ret = PTR_ERR(regmap); 114 dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 115 ret); 116 return ret; 117 } 118 119 ret = regmap_read(regmap, MT6311_SWCID, &data); 120 if (ret < 0) { 121 dev_err(&i2c->dev, "Failed to read DEVICE_ID reg: %d\n", ret); 122 return ret; 123 } 124 125 switch (data) { 126 case MT6311_E1_CID_CODE: 127 case MT6311_E2_CID_CODE: 128 case MT6311_E3_CID_CODE: 129 break; 130 default: 131 dev_err(&i2c->dev, "Unsupported device id = 0x%x.\n", data); 132 return -ENODEV; 133 } 134 135 for (i = 0; i < MT6311_MAX_REGULATORS; i++) { 136 config.dev = &i2c->dev; 137 config.regmap = regmap; 138 139 rdev = devm_regulator_register(&i2c->dev, 140 &mt6311_regulators[i], &config); 141 if (IS_ERR(rdev)) { 142 dev_err(&i2c->dev, 143 "Failed to register MT6311 regulator\n"); 144 return PTR_ERR(rdev); 145 } 146 } 147 148 return 0; 149} 150 151static const struct i2c_device_id mt6311_i2c_id[] = { 152 {"mt6311", 0}, 153 {}, 154}; 155MODULE_DEVICE_TABLE(i2c, mt6311_i2c_id); 156 157#ifdef CONFIG_OF 158static const struct of_device_id mt6311_dt_ids[] = { 159 { .compatible = "mediatek,mt6311-regulator", 160 .data = &mt6311_i2c_id[0] }, 161 {}, 162}; 163MODULE_DEVICE_TABLE(of, mt6311_dt_ids); 164#endif 165 166static struct i2c_driver mt6311_regulator_driver = { 167 .driver = { 168 .name = "mt6311", 169 .of_match_table = of_match_ptr(mt6311_dt_ids), 170 }, 171 .probe = mt6311_i2c_probe, 172 .id_table = mt6311_i2c_id, 173}; 174 175module_i2c_driver(mt6311_regulator_driver); 176 177MODULE_AUTHOR("Henry Chen <henryc.chen@mediatek.com>"); 178MODULE_DESCRIPTION("Regulator device driver for Mediatek MT6311"); 179MODULE_LICENSE("GPL v2"); 180