1414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood/*
2414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood * core.c  --  Voltage/Current Regulator framework.
3414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *
4414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood * Copyright 2007, 2008 Wolfson Microelectronics PLC.
5a5766f11cfd3a0c03450d99c8fe548c2940be884Liam Girdwood * Copyright 2008 SlimLogic Ltd.
6414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *
7a5766f11cfd3a0c03450d99c8fe548c2940be884Liam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk>
8414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *
9414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *  This program is free software; you can redistribute  it and/or modify it
10414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *  under  the terms of  the GNU General  Public License as published by the
11414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *  Free Software Foundation;  either version 2 of the  License, or (at your
12414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *  option) any later version.
13414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *
14414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood */
15414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
16414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/kernel.h>
17414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/init.h>
181130e5b3ff4a7f3f54a48d46e9d0d81b47765bd8Mark Brown#include <linux/debugfs.h>
19414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/device.h>
205a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
21f21e0e81d81b649ad309cedc7226f1bed72982e0Mark Brown#include <linux/async.h>
22414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/err.h>
23414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/mutex.h>
24414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/suspend.h>
2531aae2beeb3d601d556b6a8c39085940ad1e9f42Mark Brown#include <linux/delay.h>
2665f735082de35aa4d44e8d0afe862798d0e09e29Mark Brown#include <linux/gpio.h>
27778b28b4348af9c72bb5ac0dc129363a706325efRussell King#include <linux/gpio/consumer.h>
2869511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak#include <linux/of.h>
2965b19ce6c223287ac95bbc22b12ef5a2738472d1Mark Brown#include <linux/regmap.h>
3069511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak#include <linux/regulator/of_regulator.h>
31414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/regulator/consumer.h>
32414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/regulator/driver.h>
33414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood#include <linux/regulator/machine.h>
3465602c32ee9b5500e3cb617ccec2154ee2191898Paul Gortmaker#include <linux/module.h>
35414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
3602fa3ec01a0df7a8ccc356d8e245a9a1423b3596Mark Brown#define CREATE_TRACE_POINTS
3702fa3ec01a0df7a8ccc356d8e245a9a1423b3596Mark Brown#include <trace/events/regulator.h>
3802fa3ec01a0df7a8ccc356d8e245a9a1423b3596Mark Brown
3934abbd68efe09765465b81dfedeee9994f13302fMark Brown#include "dummy.h"
400cdfcc0f9352a4c076fbb51299e2b12a35619a51Mark Brown#include "internal.h"
4134abbd68efe09765465b81dfedeee9994f13302fMark Brown
427d51a0dbe51282f3ed13cadf6e7f13a974374be2Mark Brown#define rdev_crit(rdev, fmt, ...)					\
437d51a0dbe51282f3ed13cadf6e7f13a974374be2Mark Brown	pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
445da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches#define rdev_err(rdev, fmt, ...)					\
455da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches	pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
465da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches#define rdev_warn(rdev, fmt, ...)					\
475da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches	pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
485da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches#define rdev_info(rdev, fmt, ...)					\
495da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches	pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
505da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches#define rdev_dbg(rdev, fmt, ...)					\
515da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches	pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
525da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches
53414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic DEFINE_MUTEX(regulator_list_mutex);
54414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic LIST_HEAD(regulator_list);
55414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic LIST_HEAD(regulator_map_list);
56f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milostatic LIST_HEAD(regulator_ena_gpio_list);
57a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepaxstatic LIST_HEAD(regulator_supply_alias_list);
5821cf891a47ff5e7bd77fdc524a25072c447d56bbMark Brownstatic bool has_full_constraints;
59414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
601130e5b3ff4a7f3f54a48d46e9d0d81b47765bd8Mark Brownstatic struct dentry *debugfs_root;
611130e5b3ff4a7f3f54a48d46e9d0d81b47765bd8Mark Brown
628dc5390d4f3fd8acc73773a56fea13544e7924dcMark Brown/*
63414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood * struct regulator_map
64414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood *
65414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood * Used to provide symbolic supply names to devices.
66414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood */
67414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstruct regulator_map {
68414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	struct list_head list;
6940f9244f4da8976eeb6d5ed6313c635ba238a9d3Mark Brown	const char *dev_name;   /* The dev_name() for the consumer */
70414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	const char *supply;
71a5766f11cfd3a0c03450d99c8fe548c2940be884Liam Girdwood	struct regulator_dev *regulator;
72414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood};
73414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
74414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood/*
75f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo * struct regulator_enable_gpio
76f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo *
77f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo * Management for shared enable GPIO pin
78f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo */
79f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milostruct regulator_enable_gpio {
80f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo	struct list_head list;
81778b28b4348af9c72bb5ac0dc129363a706325efRussell King	struct gpio_desc *gpiod;
82f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo	u32 enable_count;	/* a number of enabled shared GPIO */
83f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo	u32 request_count;	/* a number of requested shared GPIO */
84f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo	unsigned int ena_gpio_invert:1;
85f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo};
86f19b00da8ed37db4e3891fe534fcf3a605a0e562Kim, Milo
87a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax/*
88a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax * struct regulator_supply_alias
89a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax *
90a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax * Used to map lookups for a supply onto an alternative device.
91a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax */
92a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepaxstruct regulator_supply_alias {
93a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax	struct list_head list;
94a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax	struct device *src_dev;
95a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax	const char *src_supply;
96a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax	struct device *alias_dev;
97a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax	const char *alias_supply;
98a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax};
99a06ccd9c3785fa5550917ae036944f4e080b5749Charles Keepax
100414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic int _regulator_is_enabled(struct regulator_dev *rdev);
1013801b86aa482d26a8ae460f67fca29e016491a86Mark Brownstatic int _regulator_disable(struct regulator_dev *rdev);
102414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic int _regulator_get_voltage(struct regulator_dev *rdev);
103414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic int _regulator_get_current_limit(struct regulator_dev *rdev);
104414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic unsigned int _regulator_get_mode(struct regulator_dev *rdev);
1057179569aeb52197fd2a9909ba226c4c9cc0e2e2aHeiko Stübnerstatic int _notifier_call_chain(struct regulator_dev *rdev,
106414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood				  unsigned long event, void *data);
107757902513019e6ee469791ff76f954b19ca8d036Mark Brownstatic int _regulator_do_set_voltage(struct regulator_dev *rdev,
108757902513019e6ee469791ff76f954b19ca8d036Mark Brown				     int min_uV, int max_uV);
1093801b86aa482d26a8ae460f67fca29e016491a86Mark Brownstatic struct regulator *create_regulator(struct regulator_dev *rdev,
1103801b86aa482d26a8ae460f67fca29e016491a86Mark Brown					  struct device *dev,
1113801b86aa482d26a8ae460f67fca29e016491a86Mark Brown					  const char *supply_name);
112414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
1131083c39346d482b9001944d05c09191027892226Mark Brownstatic const char *rdev_get_name(struct regulator_dev *rdev)
1141083c39346d482b9001944d05c09191027892226Mark Brown{
1151083c39346d482b9001944d05c09191027892226Mark Brown	if (rdev->constraints && rdev->constraints->name)
1161083c39346d482b9001944d05c09191027892226Mark Brown		return rdev->constraints->name;
1171083c39346d482b9001944d05c09191027892226Mark Brown	else if (rdev->desc->name)
1181083c39346d482b9001944d05c09191027892226Mark Brown		return rdev->desc->name;
1191083c39346d482b9001944d05c09191027892226Mark Brown	else
1201083c39346d482b9001944d05c09191027892226Mark Brown		return "";
1211083c39346d482b9001944d05c09191027892226Mark Brown}
1221083c39346d482b9001944d05c09191027892226Mark Brown
12387b2841753e1694fc96fefb467f6aff9940b07afMark Brownstatic bool have_full_constraints(void)
12487b2841753e1694fc96fefb467f6aff9940b07afMark Brown{
12575bc9641cadd2a3f91f9c2e7f2fdfdeb8bd4b1d6Mark Brown	return has_full_constraints || of_have_populated_dt();
12687b2841753e1694fc96fefb467f6aff9940b07afMark Brown}
12787b2841753e1694fc96fefb467f6aff9940b07afMark Brown
12869511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak/**
12969511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak * of_get_regulator - get a regulator device node based on supply name
13069511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak * @dev: Device pointer for the consumer (of regulator) device
13169511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak * @supply: regulator supply name
13269511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak *
13369511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak * Extract the regulator device node corresponding to the supply name.
134167d41dce7633b70aae4175fdec734e1cdd3a190Maxime Ripard * returns the device node corresponding to the regulator if found, else
13569511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak * returns NULL.
13669511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak */
13769511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayakstatic struct device_node *of_get_regulator(struct device *dev, const char *supply)
13869511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak{
13969511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	struct device_node *regnode = NULL;
14069511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	char prop_name[32]; /* 32 is max size of property name */
14169511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak
14269511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);
14369511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak
14469511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	snprintf(prop_name, 32, "%s-supply", supply);
14569511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
14669511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak
14769511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	if (!regnode) {
14816fbcc3b1139e90fe560fde5619169db74dc02c2Rajendra Nayak		dev_dbg(dev, "Looking up %s property in node %s failed",
14969511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak				prop_name, dev->of_node->full_name);
15069511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak		return NULL;
15169511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	}
15269511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak	return regnode;
15369511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak}
15469511a452e6dc6b74fe4f3671a51b1b44b9c57e3Rajendra Nayak
1556492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brownstatic int _regulator_can_change_status(struct regulator_dev *rdev)
1566492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown{
1576492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown	if (!rdev->constraints)
1586492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown		return 0;
1596492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown
1606492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown	if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
1616492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown		return 1;
1626492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown	else
1636492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown		return 0;
1646492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown}
1656492bc1b1a9cb21d28cde3c70d090c7648c8b0edMark Brown
166414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood/* Platform voltage constraint check */
167414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic int regulator_check_voltage(struct regulator_dev *rdev,
168414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood				   int *min_uV, int *max_uV)
169414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
170414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	BUG_ON(*min_uV > *max_uV);
171414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
172414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!rdev->constraints) {
1735da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "no constraints\n");
174414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -ENODEV;
175414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
176414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
1775da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "operation not allowed\n");
178414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -EPERM;
179414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
180414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
181414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (*max_uV > rdev->constraints->max_uV)
182414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		*max_uV = rdev->constraints->max_uV;
183414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (*min_uV < rdev->constraints->min_uV)
184414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		*min_uV = rdev->constraints->min_uV;
185414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
18689f425ed5bf3d4fd97e840296dccd75b8e0fe4c9Mark Brown	if (*min_uV > *max_uV) {
18789f425ed5bf3d4fd97e840296dccd75b8e0fe4c9Mark Brown		rdev_err(rdev, "unsupportable voltage range: %d-%duV\n",
18854abd335fda86d305845f9e62b4bc0997386eb66Mark Brown			 *min_uV, *max_uV);
189414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -EINVAL;
19089f425ed5bf3d4fd97e840296dccd75b8e0fe4c9Mark Brown	}
191414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
192414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	return 0;
193414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
194414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
19505fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni/* Make sure we select a voltage that suits the needs of all
19605fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni * regulator consumers
19705fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni */
19805fda3b1abc23d832144e9497fb218870927d645Thomas Petazzonistatic int regulator_check_consumers(struct regulator_dev *rdev,
19905fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni				     int *min_uV, int *max_uV)
20005fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni{
20105fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni	struct regulator *regulator;
20205fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni
20305fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni	list_for_each_entry(regulator, &rdev->consumer_list, list) {
2044aa922c024b2a194d7b68b22a66dfcf86e7838b3Mark Brown		/*
2054aa922c024b2a194d7b68b22a66dfcf86e7838b3Mark Brown		 * Assume consumers that didn't say anything are OK
2064aa922c024b2a194d7b68b22a66dfcf86e7838b3Mark Brown		 * with anything in the constraint range.
2074aa922c024b2a194d7b68b22a66dfcf86e7838b3Mark Brown		 */
2084aa922c024b2a194d7b68b22a66dfcf86e7838b3Mark Brown		if (!regulator->min_uV && !regulator->max_uV)
2094aa922c024b2a194d7b68b22a66dfcf86e7838b3Mark Brown			continue;
2104aa922c024b2a194d7b68b22a66dfcf86e7838b3Mark Brown
21105fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni		if (*max_uV > regulator->max_uV)
21205fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni			*max_uV = regulator->max_uV;
21305fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni		if (*min_uV < regulator->min_uV)
21405fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni			*min_uV = regulator->min_uV;
21505fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni	}
21605fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni
217dd8004af2b0e903b2ee9fce305cb615245fa12eeMark Brown	if (*min_uV > *max_uV) {
2189c7b4e8a8ad2624106fbf690fa97ab9c8c9bfa88Russ Dill		rdev_err(rdev, "Restricting voltage, %u-%uuV\n",
2199c7b4e8a8ad2624106fbf690fa97ab9c8c9bfa88Russ Dill			*min_uV, *max_uV);
22005fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni		return -EINVAL;
221dd8004af2b0e903b2ee9fce305cb615245fa12eeMark Brown	}
22205fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni
22305fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni	return 0;
22405fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni}
22505fda3b1abc23d832144e9497fb218870927d645Thomas Petazzoni
226414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood/* current constraint check */
227414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic int regulator_check_current_limit(struct regulator_dev *rdev,
228414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood					int *min_uA, int *max_uA)
229414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
230414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	BUG_ON(*min_uA > *max_uA);
231414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
232414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!rdev->constraints) {
2335da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "no constraints\n");
234414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -ENODEV;
235414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
236414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
2375da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "operation not allowed\n");
238414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -EPERM;
239414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
240414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
241414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (*max_uA > rdev->constraints->max_uA)
242414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		*max_uA = rdev->constraints->max_uA;
243414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (*min_uA < rdev->constraints->min_uA)
244414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		*min_uA = rdev->constraints->min_uA;
245414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
24689f425ed5bf3d4fd97e840296dccd75b8e0fe4c9Mark Brown	if (*min_uA > *max_uA) {
24789f425ed5bf3d4fd97e840296dccd75b8e0fe4c9Mark Brown		rdev_err(rdev, "unsupportable current range: %d-%duA\n",
24854abd335fda86d305845f9e62b4bc0997386eb66Mark Brown			 *min_uA, *max_uA);
249414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -EINVAL;
25089f425ed5bf3d4fd97e840296dccd75b8e0fe4c9Mark Brown	}
251414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
252414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	return 0;
253414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
254414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
255414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood/* operating mode constraint check */
2562c6082341d1896218ca974cc2bb6876e36fcba5cMark Brownstatic int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
257414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
2582c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown	switch (*mode) {
259e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell	case REGULATOR_MODE_FAST:
260e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell	case REGULATOR_MODE_NORMAL:
261e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell	case REGULATOR_MODE_IDLE:
262e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell	case REGULATOR_MODE_STANDBY:
263e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell		break;
264e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell	default:
26589f425ed5bf3d4fd97e840296dccd75b8e0fe4c9Mark Brown		rdev_err(rdev, "invalid mode %x specified\n", *mode);
266e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell		return -EINVAL;
267e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell	}
268e573520b171095c106ffbbbf4f9cbed6d9bff576David Brownell
269414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!rdev->constraints) {
2705da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "no constraints\n");
271414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -ENODEV;
272414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
273414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
2745da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "operation not allowed\n");
275414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -EPERM;
276414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
2772c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown
2782c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown	/* The modes are bitmasks, the most power hungry modes having
2792c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown	 * the lowest values. If the requested mode isn't supported
2802c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown	 * try higher modes. */
2812c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown	while (*mode) {
2822c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown		if (rdev->constraints->valid_modes_mask & *mode)
2832c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown			return 0;
2842c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown		*mode /= 2;
285414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
2862c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown
2872c6082341d1896218ca974cc2bb6876e36fcba5cMark Brown	return -EINVAL;
288414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
289414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
290414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood/* dynamic regulator mode switching constraint check */
291414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic int regulator_check_drms(struct regulator_dev *rdev)
292414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
293414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!rdev->constraints) {
2945da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "no constraints\n");
295414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -ENODEV;
296414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
297414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
2985da84fd99bb1ab1c7cd39d0cf7c08bb63931a59aJoe Perches		rdev_err(rdev, "operation not allowed\n");
299414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return -EPERM;
300414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
301414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	return 0;
302414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
303414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
304414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic ssize_t regulator_uV_show(struct device *dev,
305414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood				struct device_attribute *attr, char *buf)
306414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
307a5766f11cfd3a0c03450d99c8fe548c2940be884Liam Girdwood	struct regulator_dev *rdev = dev_get_drvdata(dev);
308414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	ssize_t ret;
309414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
310414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	mutex_lock(&rdev->mutex);
311414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev));
312414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	mutex_unlock(&rdev->mutex);
313414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
314414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	return ret;
315414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
3167ad68e2f970fd84d15ad67ce3216aed05f944a9cDavid Brownellstatic DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
317414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
318414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwoodstatic ssize_t regulator_uA_show(struct device *dev,
319414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood				struct device_attribute *attr, char *buf)
320414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
321a5766f11cfd3a0c03450d99c8fe548c2940be884Liam Girdwood	struct regulator_dev *rdev = dev_get_drvdata(dev);
322414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
323414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
324414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
3257ad68e2f970fd84d15ad67ce3216aed05f944a9cDavid Brownellstatic DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
326414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
327587cea27e4feee7365b22935b3e19e1e8906e9cbGreg Kroah-Hartmanstatic ssize_t name_show(struct device *dev, struct device_attribute *attr,
328587cea27e4feee7365b22935b3e19e1e8906e9cbGreg Kroah-Hartman			 char *buf)
329bc558a60b58f638ee0188affb627d4894a97b1c7Mark Brown{
330bc558a60b58f638ee0188affb627d4894a97b1c7Mark Brown	struct regulator_dev *rdev = dev_get_drvdata(dev);
331bc558a60b58f638ee0188affb627d4894a97b1c7Mark Brown
3321083c39346d482b9001944d05c09191027892226Mark Brown	return sprintf(buf, "%s\n", rdev_get_name(rdev));
333bc558a60b58f638ee0188affb627d4894a97b1c7Mark Brown}
334587cea27e4feee7365b22935b3e19e1e8906e9cbGreg Kroah-Hartmanstatic DEVICE_ATTR_RO(name);
335bc558a60b58f638ee0188affb627d4894a97b1c7Mark Brown
3364fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownellstatic ssize_t regulator_print_opmode(char *buf, int mode)
337414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
338414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	switch (mode) {
339414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	case REGULATOR_MODE_FAST:
340414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return sprintf(buf, "fast\n");
341414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	case REGULATOR_MODE_NORMAL:
342414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return sprintf(buf, "normal\n");
343414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	case REGULATOR_MODE_IDLE:
344414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return sprintf(buf, "idle\n");
345414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	case REGULATOR_MODE_STANDBY:
346414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return sprintf(buf, "standby\n");
347414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	}
348414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	return sprintf(buf, "unknown\n");
349414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
350414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
3514fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownellstatic ssize_t regulator_opmode_show(struct device *dev,
3524fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell				    struct device_attribute *attr, char *buf)
353414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood{
354a5766f11cfd3a0c03450d99c8fe548c2940be884Liam Girdwood	struct regulator_dev *rdev = dev_get_drvdata(dev);
355414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
3564fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell	return regulator_print_opmode(buf, _regulator_get_mode(rdev));
3574fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell}
3587ad68e2f970fd84d15ad67ce3216aed05f944a9cDavid Brownellstatic DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL);
3594fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell
3604fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownellstatic ssize_t regulator_print_state(char *buf, int state)
3614fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell{
362414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	if (state > 0)
363414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return sprintf(buf, "enabled\n");
364414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	else if (state == 0)
365414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return sprintf(buf, "disabled\n");
366414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood	else
367414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood		return sprintf(buf, "unknown\n");
368414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood}
369414c70cb91c445ec813b61e16fe4882807e40240Liam Girdwood
3704fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownellstatic ssize_t regulator_state_show(struct device *dev,
3714fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell				   struct device_attribute *attr, char *buf)
3724fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell{
3734fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell	struct regulator_dev *rdev = dev_get_drvdata(dev);
3749332546fe88fa88bf6a7d9b1dce53ff5d314934eMark Brown	ssize_t ret;
3759332546fe88fa88bf6a7d9b1dce53ff5d314934eMark Brown
3769332546fe88fa88bf6a7d9b1dce53ff5d314934eMark Brown	mutex_lock(&rdev->mutex);
3779332546fe88fa88bf6a7d9b1dce53ff5d314934eMark Brown	ret = regulator_print_state(buf, _regulator_is_enabled(rdev));
3789332546fe88fa88bf6a7d9b1dce53ff5d314934eMark Brown	mutex_unlock(&rdev->mutex);
3794fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell
3809332546fe88fa88bf6a7d9b1dce53ff5d314934eMark Brown	return ret;
3814fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell}
3827ad68e2f970fd84d15ad67ce3216aed05f944a9cDavid Brownellstatic DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
3834fca9545d17b99cdb2774716b034c62a70151bcdDavid Brownell
384853116a10544206b6b2cf42ebc9d78fba2668888David Brownellstatic ssize_t regulator_status_show(struct device *dev,
385853116a10544206b6b2cf42ebc9d78fba2668888David Brownell				   struct device_attribute *attr, char *buf)
386853116a10544206b6b2cf42ebc9d78fba2668888David Brownell{
387853116a10544206b6b2cf42ebc9d78fba2668888David Brownell	struct regulator_dev *rdev = dev_get_drvdata(dev);
388