131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll/* 231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * This program is free software; you can redistribute it and/or modify 331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * it under the terms of the GNU General Public License version 2 as 431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * published by the Free Software Foundation. 531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * 631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * This program is distributed in the hope that it will be useful, 731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * but WITHOUT ANY WARRANTY; without even the implied warranty of 831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * GNU General Public License for more details. 1031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * 1131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll * Copyright (C) 2012 ARM Limited 1231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll */ 1331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 1431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#define DRVNAME "vexpress-regulator" 1531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#define pr_fmt(fmt) DRVNAME ": " fmt 1631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 1731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/device.h> 1831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/err.h> 1931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/module.h> 2031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/of_device.h> 2131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/regulator/driver.h> 2231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/regulator/machine.h> 2331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/regulator/of_regulator.h> 2431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll#include <linux/vexpress.h> 2531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 2631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollstruct vexpress_regulator { 2731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll struct regulator_desc desc; 2831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll struct regulator_dev *regdev; 293b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll struct regmap *regmap; 3031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll}; 3131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 3231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollstatic int vexpress_regulator_get_voltage(struct regulator_dev *regdev) 3331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll{ 3431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll struct vexpress_regulator *reg = rdev_get_drvdata(regdev); 3531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll u32 uV; 363b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll int err = regmap_read(reg->regmap, 0, &uV); 3731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 3831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll return err ? err : uV; 3931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll} 4031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 4131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollstatic int vexpress_regulator_set_voltage(struct regulator_dev *regdev, 4231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll int min_uV, int max_uV, unsigned *selector) 4331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll{ 4431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll struct vexpress_regulator *reg = rdev_get_drvdata(regdev); 4531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 463b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll return regmap_write(reg->regmap, 0, min_uV); 4731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll} 4831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 4931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollstatic struct regulator_ops vexpress_regulator_ops_ro = { 5031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .get_voltage = vexpress_regulator_get_voltage, 5131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll}; 5231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 5331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollstatic struct regulator_ops vexpress_regulator_ops = { 5431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .get_voltage = vexpress_regulator_get_voltage, 5531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .set_voltage = vexpress_regulator_set_voltage, 5631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll}; 5731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 5831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollstatic int vexpress_regulator_probe(struct platform_device *pdev) 5931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll{ 6031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll struct vexpress_regulator *reg; 6131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll struct regulator_init_data *init_data; 6231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll struct regulator_config config = { }; 6331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 6431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL); 653b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll if (!reg) 663b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll return -ENOMEM; 6731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 683b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll reg->regmap = devm_regmap_init_vexpress_config(&pdev->dev); 693b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll if (IS_ERR(reg->regmap)) 703b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll return PTR_ERR(reg->regmap); 7131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 7231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll reg->desc.name = dev_name(&pdev->dev); 7331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll reg->desc.type = REGULATOR_VOLTAGE; 7431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll reg->desc.owner = THIS_MODULE; 7531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll reg->desc.continuous_voltage_range = true; 7631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 7731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); 783b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll if (!init_data) 793b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll return -EINVAL; 8031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 8131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll init_data->constraints.apply_uV = 0; 8231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll if (init_data->constraints.min_uV && init_data->constraints.max_uV) 8331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll reg->desc.ops = &vexpress_regulator_ops; 8431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll else 8531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll reg->desc.ops = &vexpress_regulator_ops_ro; 8631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 8731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll config.dev = &pdev->dev; 8831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll config.init_data = init_data; 8931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll config.driver_data = reg; 9031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll config.of_node = pdev->dev.of_node; 9131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 92abf92a3d2e868fef808d4a205371b7e5417dd0f7Jingoo Han reg->regdev = devm_regulator_register(&pdev->dev, ®->desc, &config); 933b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll if (IS_ERR(reg->regdev)) 943b9334ac835bb431e2186645230c9f1eb94b5d49Pawel Moll return PTR_ERR(reg->regdev); 9531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 9631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll platform_set_drvdata(pdev, reg); 9731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 9831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll return 0; 9931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll} 10031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 1011439afd8dba5ae552c439309286e54ffd3a97abcJingoo Hanstatic const struct of_device_id vexpress_regulator_of_match[] = { 10231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll { .compatible = "arm,vexpress-volt", }, 1039f4e45f77e8a532c8a7e39268e844821dbf7fe91Axel Lin { } 10431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll}; 10531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 10631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollstatic struct platform_driver vexpress_regulator_driver = { 10731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .probe = vexpress_regulator_probe, 10831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .driver = { 10931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .name = DRVNAME, 11031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .owner = THIS_MODULE, 11131e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll .of_match_table = vexpress_regulator_of_match, 11231e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll }, 11331e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll}; 11431e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 11531e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Mollmodule_platform_driver(vexpress_regulator_driver); 11631e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel Moll 11731e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel MollMODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); 11831e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel MollMODULE_DESCRIPTION("Versatile Express regulator"); 11931e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel MollMODULE_LICENSE("GPL"); 12031e54086dd7bb86ad40f1d76a9063f2a95866b87Pawel MollMODULE_ALIAS("platform:vexpress-regulator"); 121