Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/regulator/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 11 kB image not shown  

Quelle  max77857-regulator.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2023 Analog Devices, Inc.
 * ADI Regulator driver for the MAX77857
 * MAX77859 and MAX77831.
 */

#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/util_macros.h>

#define MAX77857_REG_INT_SRC  0x10
#define MAX77857_REG_INT_MASK  0x11
#define MAX77857_REG_CONT1  0x12
#define MAX77857_REG_CONT2  0x13
#define MAX77857_REG_CONT3  0x14

#define MAX77857_INT_SRC_OCP  BIT(0)
#define MAX77857_INT_SRC_THS  BIT(1)
#define MAX77857_INT_SRC_HARDSHORT BIT(2)
#define MAX77857_INT_SRC_OVP  BIT(3)
#define MAX77857_INT_SRC_POK  BIT(4)

#define MAX77857_ILIM_MASK  GENMASK(2, 0)
#define MAX77857_CONT1_FREQ  GENMASK(4, 3)
#define MAX77857_CONT3_FPWM  BIT(5)

#define MAX77859_REG_INT_SRC  0x11
#define MAX77859_REG_CONT1  0x13
#define MAX77859_REG_CONT2  0x14
#define MAX77859_REG_CONT3  0x15
#define MAX77859_REG_CONT5  0x17
#define MAX77859_CONT2_FPWM  BIT(2)
#define MAX77859_CONT2_INTB  BIT(3)
#define MAX77859_CONT3_DVS_START BIT(2)
#define MAX77859_VOLTAGE_SEL_MASK GENMASK(9, 0)

#define MAX77859_CURRENT_MIN  1000000
#define MAX77859_CURRENT_MAX  5000000
#define MAX77859_CURRENT_STEP  50000

enum max77857_id {
 ID_MAX77831 = 1,
 ID_MAX77857,
 ID_MAX77859,
 ID_MAX77859A,
};

static bool max77857_volatile_reg(struct device *dev, unsigned int reg)
{
 enum max77857_id id = (uintptr_t)dev_get_drvdata(dev);

 switch (id) {
 case ID_MAX77831:
 case ID_MAX77857:
  return reg == MAX77857_REG_INT_SRC;
 case ID_MAX77859:
 case ID_MAX77859A:
  return reg == MAX77859_REG_INT_SRC;
 default:
  return true;
 }
}

static const struct regmap_config max77857_regmap_config = {
 .reg_bits = 8,
 .val_bits = 8,
 .cache_type = REGCACHE_MAPLE,
 .volatile_reg = max77857_volatile_reg,
};

static int max77857_get_status(struct regulator_dev *rdev)
{
 unsigned int val;
 int ret;

 ret = regmap_read(rdev->regmap, MAX77857_REG_INT_SRC, &val);
 if (ret)
  return ret;

 if (FIELD_GET(MAX77857_INT_SRC_POK, val))
  return REGULATOR_STATUS_ON;

 return REGULATOR_STATUS_ERROR;
}

static unsigned int max77857_get_mode(struct regulator_dev *rdev)
{
 enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev);
 unsigned int regval;
 int ret;

 switch (id) {
 case ID_MAX77831:
 case ID_MAX77857:
  ret = regmap_read(rdev->regmap, MAX77857_REG_CONT3, ®val);
  if (ret)
   return ret;

  if (FIELD_GET(MAX77857_CONT3_FPWM, regval))
   return REGULATOR_MODE_FAST;

  break;
 case ID_MAX77859:
 case ID_MAX77859A:
  ret = regmap_read(rdev->regmap, MAX77859_REG_CONT2, ®val);
  if (ret)
   return ret;

  if (FIELD_GET(MAX77859_CONT2_FPWM, regval))
   return REGULATOR_MODE_FAST;

  break;
 default:
  return -EINVAL;
 }

 return REGULATOR_MODE_NORMAL;
}

static int max77857_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
 enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev);
 unsigned int reg, val;

 switch (id) {
 case ID_MAX77831:
 case ID_MAX77857:
  reg = MAX77857_REG_CONT3;
  val = MAX77857_CONT3_FPWM;
  break;
 case ID_MAX77859:
 case ID_MAX77859A:
  reg = MAX77859_REG_CONT2;
  val = MAX77859_CONT2_FPWM;
  break;
 default:
  return -EINVAL;
 }

 switch (mode) {
 case REGULATOR_MODE_FAST:
  return regmap_set_bits(rdev->regmap, reg, val);
 case REGULATOR_MODE_NORMAL:
  return regmap_clear_bits(rdev->regmap, reg, val);
 default:
  return -EINVAL;
 }
}

static int max77857_get_error_flags(struct regulator_dev *rdev,
        unsigned int *flags)
{
 unsigned int val;
 int ret;

 ret = regmap_read(rdev->regmap, MAX77857_REG_INT_SRC, &val);
 if (ret)
  return ret;

 *flags = 0;

 if (FIELD_GET(MAX77857_INT_SRC_OVP, val))
  *flags |= REGULATOR_ERROR_OVER_VOLTAGE_WARN;

 if (FIELD_GET(MAX77857_INT_SRC_OCP, val) ||
     FIELD_GET(MAX77857_INT_SRC_HARDSHORT, val))
  *flags |= REGULATOR_ERROR_OVER_CURRENT;

 if (FIELD_GET(MAX77857_INT_SRC_THS, val))
  *flags |= REGULATOR_ERROR_OVER_TEMP;

 if (!FIELD_GET(MAX77857_INT_SRC_POK, val))
  *flags |= REGULATOR_ERROR_FAIL;

 return 0;
}

static struct linear_range max77859_lin_ranges[] = {
 REGULATOR_LINEAR_RANGE(3200000, 0x0A0, 0x320, 20000)
};

static const unsigned int max77859_ramp_table[4] = {
 1000, 500, 250, 125
};

static int max77859_set_voltage_sel(struct regulator_dev *rdev,
        unsigned int sel)
{
 __be16 reg;
 int ret;

 reg = cpu_to_be16(sel);

 ret = regmap_bulk_write(rdev->regmap, MAX77859_REG_CONT3, ®, 2);
 if (ret)
  return ret;

 /* actually apply new voltage */
 return regmap_set_bits(rdev->regmap, MAX77859_REG_CONT3,
          MAX77859_CONT3_DVS_START);
}

static int max77859_get_voltage_sel(struct regulator_dev *rdev)
{
 __be16 reg;
 int ret;

 ret = regmap_bulk_read(rdev->regmap, MAX77859_REG_CONT3, ®, 2);
 if (ret)
  return ret;

 return FIELD_GET(MAX77859_VOLTAGE_SEL_MASK, __be16_to_cpu(reg));
}

static int max77859_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
{
 u32 selector;

 if (max_uA < MAX77859_CURRENT_MIN)
  return -EINVAL;

 selector = 0x12 + (max_uA - MAX77859_CURRENT_MIN) / MAX77859_CURRENT_STEP;

 selector = clamp_val(selector, 0x00, 0x7F);

 return regmap_write(rdev->regmap, MAX77859_REG_CONT5, selector);
}

static int max77859_get_current_limit(struct regulator_dev *rdev)
{
 u32 selector;
 int ret;

 ret = regmap_read(rdev->regmap, MAX77859_REG_CONT5, &selector);
 if (ret)
  return ret;

 if (selector <= 0x12)
  return MAX77859_CURRENT_MIN;

 if (selector >= 0x64)
  return MAX77859_CURRENT_MAX;

 return MAX77859_CURRENT_MIN + (selector - 0x12) * MAX77859_CURRENT_STEP;
}

static const struct regulator_ops max77859_regulator_ops = {
 .list_voltage = regulator_list_voltage_linear_range,
 .set_voltage_sel = max77859_set_voltage_sel,
 .get_voltage_sel = max77859_get_voltage_sel,
 .set_ramp_delay = regulator_set_ramp_delay_regmap,
 .get_status = max77857_get_status,
 .set_mode = max77857_set_mode,
 .get_mode = max77857_get_mode,
 .get_error_flags = max77857_get_error_flags,
};

static const struct regulator_ops max77859a_regulator_ops = {
 .list_voltage = regulator_list_voltage_linear_range,
 .set_voltage_sel = max77859_set_voltage_sel,
 .get_voltage_sel = max77859_get_voltage_sel,
 .set_current_limit = max77859_set_current_limit,
 .get_current_limit = max77859_get_current_limit,
 .set_ramp_delay = regulator_set_ramp_delay_regmap,
 .get_status = max77857_get_status,
 .set_mode = max77857_set_mode,
 .get_mode = max77857_get_mode,
 .get_error_flags = max77857_get_error_flags,
};

static const struct regulator_ops max77857_regulator_ops = {
 .list_voltage = regulator_list_voltage_linear_range,
 .set_voltage_sel = regulator_set_voltage_sel_regmap,
 .get_voltage_sel = regulator_get_voltage_sel_regmap,
 .set_ramp_delay = regulator_set_ramp_delay_regmap,
 .get_status = max77857_get_status,
 .set_mode = max77857_set_mode,
 .get_mode = max77857_get_mode,
 .get_error_flags = max77857_get_error_flags,
};

static struct linear_range max77857_lin_ranges[] = {
 REGULATOR_LINEAR_RANGE(4485000, 0x3D, 0xCC, 73500)
};

static const unsigned int max77857_switch_freq[] = {
 1200000, 1500000, 1800000, 2100000
};

#define RAMAP_DELAY_INIT_VAL 1333

static const unsigned int max77857_ramp_table[2][4] = {
 { RAMAP_DELAY_INIT_VAL, 667, 333, 227 }, /* when switch freq is 1.8MHz or 2.1MHz */
 { 1166, 667, 333, 167 }, /* when switch freq is 1.2MHz or 1.5MHz */
};

static struct regulator_desc max77857_regulator_desc = {
 .ops = &max77857_regulator_ops,
 .name = "max77857",
 .linear_ranges = max77857_lin_ranges,
 .n_linear_ranges = ARRAY_SIZE(max77857_lin_ranges),
 .vsel_mask = 0xFF,
 .vsel_reg = MAX77857_REG_CONT2,
 .ramp_delay_table = max77857_ramp_table[0],
 .n_ramp_values = ARRAY_SIZE(max77857_ramp_table[0]),
 .ramp_reg = MAX77857_REG_CONT3,
 .ramp_mask = GENMASK(1, 0),
 .ramp_delay = RAMAP_DELAY_INIT_VAL,
 .owner = THIS_MODULE,
};

static void max77857_calc_range(struct device *dev, enum max77857_id id)
{
 struct linear_range *range;
 unsigned long vref_step;
 u32 rtop = 0;
 u32 rbot = 0;

 device_property_read_u32(dev, "adi,rtop-ohms", &rtop);
 device_property_read_u32(dev, "adi,rbot-ohms", &rbot);

 if (!rbot || !rtop)
  return;

 switch (id) {
 case ID_MAX77831:
 case ID_MAX77857:
  range = max77857_lin_ranges;
  vref_step = 4900UL;
  break;
 case ID_MAX77859:
 case ID_MAX77859A:
  range = max77859_lin_ranges;
  vref_step = 1250UL;
  break;
 }

 range->step = DIV_ROUND_CLOSEST(vref_step * (rbot + rtop), rbot);
 range->min = range->step * range->min_sel;
}

static int max77857_probe(struct i2c_client *client)
{
 const struct i2c_device_id *i2c_id;
 struct device *dev = &client->dev;
 struct regulator_config cfg = { };
 struct regulator_dev *rdev;
 struct regmap *regmap;
 enum max77857_id id;
 u32 switch_freq = 0;
 int ret;

 i2c_id = i2c_client_get_device_id(client);
 if (!i2c_id)
  return -EINVAL;

 id = i2c_id->driver_data;

 dev_set_drvdata(dev, (void *)id);

 if (id == ID_MAX77859 || id == ID_MAX77859A) {
  max77857_regulator_desc.ops = &max77859_regulator_ops;
  max77857_regulator_desc.linear_ranges = max77859_lin_ranges;
  max77857_regulator_desc.ramp_delay_table = max77859_ramp_table;
  max77857_regulator_desc.ramp_delay = max77859_ramp_table[0];
 }

 if (id == ID_MAX77859A)
  max77857_regulator_desc.ops = &max77859a_regulator_ops;

 max77857_calc_range(dev, id);

 regmap = devm_regmap_init_i2c(client, &max77857_regmap_config);
 if (IS_ERR(regmap))
  return dev_err_probe(dev, PTR_ERR(regmap),
         "cannot initialize regmap\n");

 device_property_read_u32(dev, "adi,switch-frequency-hz", &switch_freq);
 if (switch_freq) {
  switch_freq = find_closest(switch_freq, max77857_switch_freq,
        ARRAY_SIZE(max77857_switch_freq));

  if (id == ID_MAX77831 && switch_freq == 3)
   switch_freq = 2;

  switch (id) {
  case ID_MAX77831:
  case ID_MAX77857:
   ret = regmap_update_bits(regmap, MAX77857_REG_CONT1,
       MAX77857_CONT1_FREQ, switch_freq);

   if (switch_freq >= 2)
    break;

   max77857_regulator_desc.ramp_delay_table = max77857_ramp_table[1];
   max77857_regulator_desc.ramp_delay = max77857_ramp_table[1][0];
   break;
  case ID_MAX77859:
  case ID_MAX77859A:
   ret = regmap_update_bits(regmap, MAX77859_REG_CONT1,
       MAX77857_CONT1_FREQ, switch_freq);
   break;
  }
  if (ret)
   return ret;
 }

 cfg.dev = dev;
 cfg.driver_data = (void *)id;
 cfg.regmap = regmap;
 cfg.init_data = of_get_regulator_init_data(dev, dev->of_node,
         &max77857_regulator_desc);
 if (!cfg.init_data)
  return -ENOMEM;

 rdev = devm_regulator_register(dev, &max77857_regulator_desc, &cfg);
 if (IS_ERR(rdev))
  return dev_err_probe(dev, PTR_ERR(rdev),
         "cannot register regulator\n");

 return 0;
}

static const struct i2c_device_id max77857_id[] = {
 { "max77831", ID_MAX77831 },
 { "max77857", ID_MAX77857 },
 { "max77859", ID_MAX77859 },
 { "max77859a", ID_MAX77859A },
 { }
};
MODULE_DEVICE_TABLE(i2c, max77857_id);

static const struct of_device_id max77857_of_id[] = {
 { .compatible = "adi,max77831", .data = (void *)ID_MAX77831 },
 { .compatible = "adi,max77857", .data = (void *)ID_MAX77857 },
 { .compatible = "adi,max77859", .data = (void *)ID_MAX77859 },
 { .compatible = "adi,max77859a", .data = (void *)ID_MAX77859A },
 { }
};
MODULE_DEVICE_TABLE(of, max77857_of_id);

static struct i2c_driver max77857_driver = {
 .driver = {
  .name = "max77857",
  .of_match_table = max77857_of_id,
 },
 .id_table = max77857_id,
 .probe = max77857_probe,
};
module_i2c_driver(max77857_driver);

MODULE_DESCRIPTION("Analog Devices MAX77857 Buck-Boost Converter Driver");
MODULE_AUTHOR("Ibrahim Tilki ");
MODULE_AUTHOR("Okan Sahin ");
MODULE_LICENSE("GPL");

Messung V0.5
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.