1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Functions to access SY3686A power management chip voltages 4 // 5 // Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/ 6 // 7 // Authors: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com> 8 // Alistair Francis <alistair@alistair23.me> 9 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 #include <linux/regmap.h> 13 #include <linux/gpio/consumer.h> 14 #include <linux/mfd/sy7636a.h> 15 16 #define SY7636A_POLL_ENABLED_TIME 500 17 18 static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev) 19 { 20 int ret; 21 unsigned int val, val_h; 22 23 ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, &val); 24 if (ret) 25 return ret; 26 27 ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, &val_h); 28 if (ret) 29 return ret; 30 31 val |= (val_h << VCOM_ADJUST_CTRL_SHIFT); 32 33 return (val & VCOM_ADJUST_CTRL_MASK) * VCOM_ADJUST_CTRL_SCAL; 34 } 35 36 static int sy7636a_get_status(struct regulator_dev *rdev) 37 { 38 struct sy7636a *sy7636a = rdev_get_drvdata(rdev); 39 int ret = 0; 40 41 ret = gpiod_get_value_cansleep(sy7636a->pgood_gpio); 42 if (ret < 0) 43 dev_err(&rdev->dev, "Failed to read pgood gpio: %d\n", ret); 44 45 return ret; 46 } 47 48 static const struct regulator_ops sy7636a_vcom_volt_ops = { 49 .get_voltage = sy7636a_get_vcom_voltage_op, 50 .enable = regulator_enable_regmap, 51 .disable = regulator_disable_regmap, 52 .is_enabled = regulator_is_enabled_regmap, 53 .get_status = sy7636a_get_status, 54 }; 55 56 static const struct regulator_desc desc = { 57 .name = "vcom", 58 .id = 0, 59 .ops = &sy7636a_vcom_volt_ops, 60 .type = REGULATOR_VOLTAGE, 61 .owner = THIS_MODULE, 62 .enable_reg = SY7636A_REG_OPERATION_MODE_CRL, 63 .enable_mask = SY7636A_OPERATION_MODE_CRL_ONOFF, 64 .poll_enabled_time = SY7636A_POLL_ENABLED_TIME, 65 .regulators_node = of_match_ptr("regulators"), 66 .of_match = of_match_ptr("vcom"), 67 }; 68 69 static int sy7636a_regulator_probe(struct platform_device *pdev) 70 { 71 struct sy7636a *sy7636a = dev_get_drvdata(pdev->dev.parent); 72 struct regulator_config config = { }; 73 struct regulator_dev *rdev; 74 struct gpio_desc *gdp; 75 int ret; 76 77 if (!sy7636a) 78 return -EPROBE_DEFER; 79 80 platform_set_drvdata(pdev, sy7636a); 81 82 gdp = devm_gpiod_get(sy7636a->dev, "epd-pwr-good", GPIOD_IN); 83 if (IS_ERR(gdp)) { 84 dev_err(sy7636a->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp)); 85 return PTR_ERR(gdp); 86 } 87 88 sy7636a->pgood_gpio = gdp; 89 90 ret = regmap_write(sy7636a->regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0); 91 if (ret) { 92 dev_err(sy7636a->dev, "Failed to initialize regulator: %d\n", ret); 93 return ret; 94 } 95 96 config.dev = &pdev->dev; 97 config.dev->of_node = sy7636a->dev->of_node; 98 config.driver_data = sy7636a; 99 config.regmap = sy7636a->regmap; 100 101 rdev = devm_regulator_register(&pdev->dev, &desc, &config); 102 if (IS_ERR(rdev)) { 103 dev_err(sy7636a->dev, "Failed to register %s regulator\n", 104 pdev->name); 105 return PTR_ERR(rdev); 106 } 107 108 return 0; 109 } 110 111 static const struct platform_device_id sy7636a_regulator_id_table[] = { 112 { "sy7636a-regulator", }, 113 { } 114 }; 115 MODULE_DEVICE_TABLE(platform, sy7636a_regulator_id_table); 116 117 static struct platform_driver sy7636a_regulator_driver = { 118 .driver = { 119 .name = "sy7636a-regulator", 120 }, 121 .probe = sy7636a_regulator_probe, 122 .id_table = sy7636a_regulator_id_table, 123 }; 124 module_platform_driver(sy7636a_regulator_driver); 125 126 MODULE_AUTHOR("Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>"); 127 MODULE_DESCRIPTION("SY7636A voltage regulator driver"); 128 MODULE_LICENSE("GPL v2"); 129