linux regulator接口驱动demo

本文档详细介绍了MPS2022电源管理芯片的设备树配置、驱动源代码以及中断处理。驱动程序实现了对芯片的读写操作,包括电压和电流监测、状态检查以及中断处理。同时,还展示了如何注册和配置输出调节器,以及诊断输入和输出的状态。
摘要由CSDN通过智能技术生成

设备树

&i2c0 {
	mps2022_cam_pp: pp@21 {
		reg = <0x21>;
		compatible = "mps,mps2022";

		device-supply = <&_3v3_db_ivi>;
		camera-supply = <&_8v_cam>;

		/* power down bit of mps2022 */
		gpio = <&gpio6 12 GPIO_ACTIVE_HIGH>;

		/* parent IRQ is gpio6 31 */
		interrupt-parent = <&gpio6>;
		interrupts = <31 IRQ_TYPE_EDGE_BOTH>;

		status = "disabled";

		regulators {
			cam1_regulator: output1 {
				regulator-name = "cam1";
			};

			cam2_regulator: output2 {
				regulator-name = "cam2";
			};
		};
	};
};

&xxx_x_des {
	#address-cells = <1>;
	#size-cells = <0>;

	poc-supply = <&cam2_regulator>;
};

驱动源代码


#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>

#ifdef CONFIG_DIAG_CLASS
#include <linux/diagnostic.h>
#include <linux/diagnostic/diagnostic_mps2022.h>
#include <linux/wait.h>
#endif /* CONFIG_DIAG_CLASS */


#define MPS2022_OUTPUT_COUNT	(3)

/* MPS2022_REG_MASK */
#define MPS2022_MASK_OVTST_BIT	(BIT(7))
#define MPS2022_MASK_ACCM_BIT	(BIT(6))
#define MPS2022_MASK_TSM_BIT	(BIT(5))
#define MPS2022_MASK_VDDM_BIT	(BIT(4))
#define MPS2022_MASK_VINM_BIT	(BIT(3))
#define MPS2022_MASK_OCM_BIT	(BIT(2))
#define MPS2022_MASK_OVM_BIT	(BIT(1))
#define MPS2022_MASK_UVM_BIT	(BIT(0))

/* MPS2022_REG_CONFIG */
#define MPS2022_CONFIG_ENC_BIT	(BIT(5))
#define MPS2022_CONFIG_CLR_BIT	(BIT(4))
#define MPS2022_CONFIG_EN3_BIT	(BIT(3))
#define MPS2022_CONFIG_EN2_BIT	(BIT(2))
#define MPS2022_CONFIG_EN1_BIT	(BIT(1))
#define MPS2022_CONFIG_EN0_BIT	(BIT(0))
#define MPS2022_CONFIG_EN_BITS	(MPS2022_CONFIG_EN3_BIT | \
					MPS2022_CONFIG_EN2_BIT | \
					MPS2022_CONFIG_EN1_BIT | \
					MPS2022_CONFIG_EN0_BIT)

/* MPS2022_REG_ID */
#define MPS2022_ID_BITS	(BIT(5) | BIT(4))
#define MPS2022_ID_SHIFT	(4)
#define MPS2022_REVISION_BITS	(BIT(3) | BIT(2) | BIT(1) | BIT(0))

/* MPS2022_REG_STAT1 */
#define MPS2022_STAT1_ISET_BIT	(BIT(5))
#define MPS2022_STAT1_ACC_BIT	(BIT(4))
#define MPS2022_STAT1_OVIN_BIT	(BIT(3))
#define MPS2022_STAT1_UVIN_BIT	(BIT(2))
#define MPS2022_STAT1_OVDD_BIT	(BIT(1))
#define MPS2022_STAT1_UVDD_BIT	(BIT(0))

/* MPS2022_REG_STAT2 */
#define MPS2022_STAT2_COUNT	(4)
#define MPS2022_STAT2_TS_BIT	(BIT(3))
#define MPS2022_STAT2_OC_BIT	(BIT(2))
#define MPS2022_STAT2_OV_BIT	(BIT(1))
#define MPS2022_STAT2_UV_BIT	(BIT(0))

/* Registers */
enum {
	MPS2022_REG_DEV_REV = 0,
	MPS2022_REG_DEV_STAT,
	MPS2022_REG_ERR_FLAG1,
	MPS2022_REG_ERR_FLAG2,
	MPS2022_REG_DEV_CTRL,
	MPS2022_REG_MON_VOUT1,
	MPS2022_REG_MON_VOUT2,
	MPS2022_REG_MON_IOUT1,
	MPS2022_REG_MON_IOUT2,
	MPS2022_REG_SET_VOUT1,
	MPS2022_REG_SET_VOUT2,
	MPS2022_REG_SET_VPREBOOST,
	MPS2022_REG_SET_VPREBOOST_ON,
	MPS2022_REG_SET_PG_UVOV,
	MPS2022_REG_SET_IOUT_LIM1,
	MPS2022_REG_SET_IOUT_LIM2,
};

struct mps2022_output {
	struct	regulator_desc	desc;
	struct	regulator_dev	*dev;
	struct	device_node	*np;
	const	char		*supply_name;
	bool			enabled;
	bool			exist;
};

struct mps2022_config {
	struct gpio_desc 	*en_gpio;
	struct regulator 	*vdd;
	struct regulator 	*vin;
	struct mps2022_output 	outputs[MPS2022_OUTPUT_COUNT];
};

struct mps2022_data {
	struct	i2c_client	*client;
	struct	device		*dev;
	struct	regmap		*regmap;
	struct	mps2022_config	*config;
	int	id;

	irq_handler_t irq_thread;
	unsigned long irqflags;

#ifdef CONFIG_DIAG_CLASS
	uint32_t		diag_status;
	uint32_t		adc_status;
	struct diag_classdev	diag_cdev;
	struct mutex		diag_lock;
	wait_queue_head_t	adc_queue;
	bool			adc_done;
#endif /* CONFIG_DIAG_CLASS */
};

static const struct regmap_config mps2022_regmap = {
	.reg_bits = 8,
	.val_bits = 16,
	.max_register = 0x0f,
};

const char* mps2022_id[] = {
	"MPS2022",
};

static unsigned char mps2022_crc8_pec_check(unsigned char* ptr,unsigned char len)
{
	unsigned char i;
	static const unsigned char crcpoly = 0x07;
	unsigned char crc = 0x00;

	while(len--)
	{
		crc ^= *ptr++;
		for (i=8; i>0; --i)
		{
			if (crc & 0x80)
				crc = (crc << 1) ^ crcpoly;
			else
				crc = (crc << 1);
		}
	}

	return crc;
}

/**
* mps2022_regmap_read() - Read a value from a single register
*
* @map: Register map to read from
* @reg: Register to be read from
* @val: Pointer to store read value
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
static int mps2022_regmap_read(struct mps2022_data *mps2022, unsigned int reg, unsigned int *val)
{
	unsigned  char data_ptr[4]={0x42,0,0x43,0};
	unsigned char pec_data;
	unsigned  char crc,retry_cnt=0;
	int ret = 0;

	data_ptr[1] = reg;
retry:
	ret = regmap_read(mps2022->regmap, reg, val);
	if (ret < 0) {
		dev_err( mps2022->dev,"Failed to read mps2022 reg[0x%x] value[0x%x]\n", reg,*val);
		return ret;
	}
	pec_data = *val & 0xff;
	*val = (*val  >> 8) & 0xff;
	data_ptr[3] = *val;
	crc = mps2022_crc8_pec_check(data_ptr,sizeof(data_ptr));
	
	/* PEC data check, if check failed then retry 3 times */
	if( crc != pec_data ){
		if(retry_cnt<3){
			retry_cnt++;
			goto retry;
		}else{
			dev_err( mps2022->dev,"The PEC data  is mismatch when reading mps2022 reg[0x%x]\n", reg);
			return -1;
		}
	}
	
	return ret;
}

/**
 * mps2022_regmap_write() - Write a value to a single register
 *
 * @map: Register map to write to
 * @reg: Register to write to
 * @val: Value to be written
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
static int mps2022_regmap_write(struct mps2022_data *mps2022, unsigned int reg, unsigned int val)
{
	unsigned  char data_ptr[3]={0x42,0,0};
	unsigned int pec_data;
	unsigned  char crc;
	int ret = 0;

	data_ptr[1] = reg;
	data_ptr[2] = val;

	crc =  mps2022_crc8_pec_check(data_ptr,sizeof(data_ptr));
	pec_data =  (val << 8) |  crc;
	
	ret = regmap_write(mps2022->regmap,reg,pec_data);
	if (ret < 0) {
		dev_err(mps2022->dev, "Failed to write mps2022 reg[0x%x] value[0x%x]\n", reg,val);
		return ret;
	}
	return ret;
}

static int mps2022_find_which_output(struct regulator_dev *rdev,
						struct mps2022_data *mps2022)
{
	int i;

	for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
		if (rdev == mps2022->config->outputs[i].dev)
			return i;
	}

	dev_err(mps2022->dev, "Regulator is not valid\n");
	return -EINVAL;
}

static int mps2022_is_enabled(struct regulator_dev *rdev)
{
	struct mps2022_data *mps2022 = rdev_get_drvdata(rdev);
	int i;

	i = mps2022_find_which_output(rdev, mps2022);
	if (i < 0)
		return i;

	return mps2022->config->outputs[i].enabled;
}

static int mps2022_set_output(struct mps2022_data *mps2022, int num,
								bool state)
{
	int ret = 0;
	unsigned int val = 0;

	ret = mps2022_regmap_read(mps2022,MPS2022_REG_DEV_CTRL,&val);
	if (ret < 0) {
		dev_err(mps2022->dev, "Failed to read register 0x%x: 0x%x\n",
						MPS2022_REG_DEV_CTRL, ret);
		return ret;
	}
	
	/* enable/disable LDO output */
	if(state){
		ret = mps2022_regmap_write(mps2022, MPS2022_REG_DEV_CTRL,val |(1 << (6-num)));
		dev_info(mps2022->dev, "Enabe LDO%d output\n",num+1);
	}else{
		ret = mps2022_regmap_write(mps2022, MPS2022_REG_DEV_CTRL,val &~(1 << (6-num)));
		dev_info(mps2022->dev, "Disable LDO%d output\n",num+1);
	}
	if (ret < 0) {
		dev_err(mps2022->dev, "Failed to update register 0x%x: 0x%x\n",
						MPS2022_REG_DEV_CTRL, ret);
		return ret;
	}

	mps2022->config->outputs[num].enabled = state;
	return 0;
}

static int mps2022_enable(struct regulator_dev *rdev)
{
	struct mps2022_data *mps2022 = rdev_get_drvdata(rdev);
	int i;

	i = mps2022_find_which_output(rdev, mps2022);
	if (i < 0)
		return i;

	return mps2022_set_output(mps2022, i, true);
}

static int mps2022_disable(struct regulator_dev *rdev)
{
	struct mps2022_data *mps2022 = rdev_get_drvdata(rdev);
	int i;

	i = mps2022_find_which_output(rdev, mps2022);
	if (i < 0)
		return i;

	return mps2022_set_output(mps2022, i, false);
}

static struct regulator_ops mps2022_regulator_ops = {
	.enable = mps2022_enable,
	.disable = mps2022_disable,
	.is_enabled = mps2022_is_enabled,
};

/* mps2022_config_output: Configure output regulators */
static int mps2022_config_output(struct mps2022_data *mps2022,
				  struct device_node *output_np)
{
	struct device *dev = mps2022->dev;
	struct mps2022_config *config = mps2022->config;
	struct regulator_init_data *init_data;
	struct regulator_config reg_cfg = { };
	int i, ret;

	sscanf(output_np->name, "output%d", &i);

	if (i > MPS2022_OUTPUT_COUNT) {
		dev_err(dev, "Output node named %s is not valid\n",
			output_np->name);
		return -EINVAL;
	}

	/* real output number (1-3) to array output number (0-2) */
	i = i - 1;

	if (config->outputs[i].exist == true) {
		dev_err(dev, "Output node named %s is duplicated\n",
			output_np->name);
		return -EINVAL;
	}

	config->outputs[i].exist = true;

	if (of_find_property(output_np, "default-state-on", NULL))
		config->outputs[i].enabled = true;
	else
		config->outputs[i].enabled = false;

	config->outputs[i].np = output_np;

	init_data = of_get_regulator_init_data(dev, output_np,
					       &config->outputs[i].desc);
	if (!init_data) {
		dev_err(dev, "Failed to allocate regulator init data\n");
		return -ENOMEM;
	}

	config->outputs[i].supply_name = init_data->constraints.name;

	config->outputs[i].desc.name =
		devm_kstrdup(dev, config->outputs[i].supply_name, GFP_KERNEL);
	if (config->outputs[i].desc.name == NULL) {
		dev_err(dev, "Failed to allocate supply name\n");
		return -ENOMEM;
	}

	config->outputs[i].desc.type = REGULATOR_VOLTAGE;
	config->outputs[i].desc.owner = THIS_MODULE;
	config->outputs[i].desc.ops = &mps2022_regulator_ops;

	reg_cfg.dev = dev;
	reg_cfg.init_data = init_data;
	reg_cfg.driver_data = mps2022;
	reg_cfg.of_node = output_np;

	config->outputs[i].dev = devm_regulator_register(dev,
					&config->outputs[i].desc, &reg_cfg);
	if (IS_ERR(config->outputs[i].dev)) {
		ret = PTR_ERR(config->outputs[i].dev);
		dev_err(dev, "Failed to register regulator: %d\n", ret);
		return ret;
	}

	dev_dbg(dev, "Output node named %s found\n", output_np->name);
	return 0;
}

static int mps2022_set_output_default(struct mps2022_data *mps2022,int num)
{
	int ret = 0;
	
	ret = mps2022_regmap_write(mps2022, MPS2022_REG_SET_VOUT1+num,0x63);
	if (ret < 0) {
		dev_err(mps2022->dev, "Failed to update register 0x%x: 0x%x\n",
						MPS2022_REG_SET_VOUT1+num, ret);
		return ret;
	}

	dev_info(mps2022->dev, "Set LDO%d as default output\n",num+1);
	return ret;
}

/*
 * of_get_mps2022_config - extract mps2022_config structure info
 * @dev: device requesting for mps2022_config
 *
 * Populates mps2022_config structure by extracting drvdata from
 * device tree node, returns a pointer to the populated structure
 */
static struct mps2022_config * of_get_mps2022_config(
						struct mps2022_data *mps2022)
{
	struct device *dev = mps2022->dev;
	struct mps2022_config *config;
	struct device_node *regulators_np, *regulator_child;
	int ret, i = 0;

	config = devm_kzalloc(dev, sizeof(struct mps2022_config), GFP_KERNEL);
	if (!config)
		return ERR_PTR(-ENOMEM);

	mps2022->config = config;

	config->vdd = devm_regulator_get(dev, "device");
	if (IS_ERR(config->vdd)) {
		ret = PTR_ERR(config->vdd);
		dev_err(dev,
			"cannot find correct \"device-supply\" parameter: %d\n",
			ret);
		return ERR_PTR(ret);
	}

	config->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
	if (IS_ERR(config->en_gpio)) {
		ret = PTR_ERR(config->en_gpio);
		dev_err(dev, "failed to get enable gpio: %d", ret);
		return ERR_PTR(ret);
	}

	config->vin = devm_regulator_get(dev, "camera");
	if (IS_ERR(config->vin)) {
		ret = PTR_ERR(config->vin);
		dev_err(dev,
			"cannot find correct \"camera-supply\" parameter: %d\n",
			ret);
		return ERR_PTR(ret);
	}

	msleep(100);

	regulators_np = of_get_child_by_name(dev->of_node, "regulators");
	if (!regulators_np) {
		dev_err(dev,
			"cannot find correct \"regulators\" node point\n");
		return ERR_PTR(-EINVAL);
	}

	for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
		config->outputs[i].exist = false;
	}

	i = 0;
	for_each_child_of_node(regulators_np, regulator_child) {
		if (i >= MPS2022_OUTPUT_COUNT) {
			dev_err(dev, "too much output regulators provided\n");
			return ERR_PTR(-EINVAL);
		}
		ret = mps2022_config_output(mps2022, regulator_child);
		if (ret < 0)
			return ERR_PTR(ret);

		mps2022_set_output_default(mps2022,i);
		if (ret < 0)
			return ERR_PTR(ret);

		ret = mps2022_set_output(mps2022, i,
						config->outputs[i].enabled);
		if (ret < 0)
			return ERR_PTR(ret);

		i++;
	}

	return config;
}

static int mps2022_diag_inputs(struct mps2022_data *mps2022)
{
	int ret;
	uint8_t status;

#ifdef CONFIG_DIAG_CLASS
	uint32_t adc_res;
#endif /* CONFIG_DIAG_CLASS */

	ret = regmap_read(mps2022->regmap, MPS2022_REG_ERR_FLAG1,
						(unsigned int *)&status);
	if (ret < 0) {
		dev_err(mps2022->dev, "Failed to read stat1: %d\n", ret);
		return ret;
	}

	if (status & MPS2022_STAT1_ISET_BIT)
		dev_warn(mps2022->dev, "ISET pin open or shorted\n");

	if (status & MPS2022_STAT1_ACC_BIT) {
		dev_dbg(mps2022->dev, "ADC conversions completed\n");

#ifdef CONFIG_DIAG_CLASS
		/* read adc results */
		ret = regmap_bulk_read(mps2022->regmap, MPS2022_REG_ERR_FLAG1,
					&adc_res, MPS2022_OUTPUT_COUNT);
		if (ret < 0) {
			dev_err(mps2022->dev,
				"fail to read adc registers: %d\n", ret);
			return ret;
		}

		mutex_lock(&mps2022->diag_lock);
		mps2022->adc_status = adc_res;
		mps2022->adc_done = true;
		mutex_unlock(&mps2022->diag_lock);

		/* waking up adc_conversion_show function */
		wake_up(&mps2022->adc_queue);
#endif /* CONFIG_DIAG_CLASS */

		/*
		 * masking this bit
		 * it is not relevant to inform user that adc conversion is
		 * complete while he is already waiting for the conversion
		 * result through adc_conversion file
		 */
		status &= ~MPS2022_STAT1_ACC_BIT;
	}

	if (status & MPS2022_STAT1_OVIN_BIT)
		dev_warn(mps2022->dev, "VIN > 16.5V, outputs off\n");

	if (status & MPS2022_STAT1_UVIN_BIT)
		dev_warn(mps2022->dev, "VIN 鈮?2.7V, outputs off\n");

	if (status & MPS2022_STAT1_OVDD_BIT)
		dev_warn(mps2022->dev, "VDD > 5.7V, outputs off\n");

	if (status & MPS2022_STAT1_UVDD_BIT)
		dev_warn(mps2022->dev, "VDD 鈮?2.7V, outputs off\n");

	return (int)status;
}

static int mps2022_diag_outputs(struct mps2022_data *mps2022)
{
	int ret, i;
	uint16_t status;

	ret = regmap_bulk_read(mps2022->regmap, MPS2022_REG_ERR_FLAG1,
						(unsigned int *)&status, 2);
	if (ret < 0) {
		dev_err(mps2022->dev, "fail to read stat2: %d\n", ret);
		return ret;
	}

	/*
	 * i + 1 inside loop is meant to convert array output number (0-3) to
	 * real output number (1-4)
	 */
	for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
		if (status & (MPS2022_STAT2_TS_BIT <<
						(i*MPS2022_STAT2_COUNT)))
			dev_warn(mps2022->dev,
				"Channel %d in thermal shutdown\n", i + 1);

		if (status & (MPS2022_STAT2_OC_BIT <<
						(i*MPS2022_STAT2_COUNT)))
			dev_warn(mps2022->dev,
				"Channel %d in current limit (short-to-ground)\n",
				i + 1);

		if (status & (MPS2022_STAT2_OV_BIT <<
						(i*MPS2022_STAT2_COUNT)))
			dev_warn(mps2022->dev,
				"Channel %d voltage is higher than the input voltage (short-to-battery)\n",
				i + 1);

		if (status & (MPS2022_STAT2_UV_BIT <<
				(i*MPS2022_STAT2_COUNT))) {
			/*
			 * masking this bit when the corresponding channel is
			 * not enabled
			 */
			if ((!mps2022->config->outputs[i].enabled)) {
				status &= ~(MPS2022_STAT2_UV_BIT <<
						(i*MPS2022_STAT2_COUNT));
			} else {
				dev_warn(mps2022->dev,
					"Channel %d undervoltage (shorted output or thermal shutdown)\n",
					i + 1);
			}
		}
	}

	return (int)status;
}

static irqreturn_t mps2022_irq_thread(int irq, void *data)
{
	struct mps2022_data *mps2022 = data;
	int ret;

#ifdef CONFIG_DIAG_CLASS
	uint32_t diag_status;
#endif /* CONFIG_DIAG_CLASS */

	dev_dbg(mps2022->dev, "IRQ caught\n");

	ret = mps2022_diag_inputs(mps2022);
	if (ret < 0)
		goto fail;

#ifdef CONFIG_DIAG_CLASS
	diag_status = ret & MPS2022_DIAGNOSTIC_INPUT_MASK;
#endif /* CONFIG_DIAG_CLASS */

	ret = mps2022_diag_outputs(mps2022);
	if (ret < 0)
		goto fail;

#ifdef CONFIG_DIAG_CLASS
	diag_status |= (ret & MPS2022_DIAGNOSTIC_OUTPUT_MASK) <<
					MPS2022_DIAGNOSTIC_OUTPUT_SHIFT;

	/* notify user space if there is an issue */
//	if (diag_status) {
		mutex_lock(&mps2022->diag_lock);
		mps2022->diag_status = diag_status;
		mutex_unlock(&mps2022->diag_lock);
		diag_monitoring_notify(&mps2022->diag_cdev);
//	}
#endif /* CONFIG_DIAG_CLASS */

fail:
	return IRQ_HANDLED;
}

#ifdef CONFIG_DIAG_CLASS
int mps2022_sysfs_get_diag_status(struct diag_classdev *diag_cdev)
{
	struct mps2022_data *mps2022 =
		container_of(diag_cdev, struct mps2022_data, diag_cdev);
	uint32_t ret;

	mutex_lock(&mps2022->diag_lock);
	ret = mps2022->diag_status;
//	mps2022->diag_status = 0;
	mutex_unlock(&mps2022->diag_lock);

	return ret;
}

static ssize_t adc_conversion_show(struct device *dev,
			 struct device_attribute *attr, char *buf)
{
	struct mps2022_data *mps2022 = dev_get_drvdata(dev->parent);
	uint32_t ret;
	unsigned int val;

	/* to start adc conversion */
	ret = regmap_read(mps2022->regmap, MPS2022_REG_MON_VOUT1, &val);
	if (ret < 0) {
		dev_err(mps2022->dev, "Failed to read adc1: %d\n", ret);
		return ret;
	}

	/* wait for adc conversion to be done */
	wait_event_timeout(mps2022->adc_queue,
				mps2022->adc_done == true,
				msecs_to_jiffies(1000));
	mps2022->adc_done = false;

	mutex_lock(&mps2022->diag_lock);
	ret = mps2022->adc_status;
	mps2022->adc_status = 0;
	mutex_unlock(&mps2022->diag_lock);

	return sprintf(buf, "0x%08x\n", ret);
}
static DEVICE_ATTR_RO(adc_conversion);


static struct attribute *mps2022_attr[] = {
	&dev_attr_adc_conversion.attr,
	NULL
};
static struct attribute_group mps2022_attr_grp  = {
	.attrs = mps2022_attr,
};

static const struct attribute_group *mps2022_attr_groups[] = {
	&mps2022_attr_grp,
	NULL,
};
#endif /* CONFIG_DIAG_CLASS */

static int mps2022_probe(struct i2c_client *client,
			     const struct i2c_device_id *id)
{
	struct mps2022_data *mps2022;
	struct resource *res;
	int ret;

	mps2022 = devm_kzalloc(&client->dev, sizeof(*mps2022), GFP_KERNEL);
	if (!mps2022) {
		ret = -ENOMEM;
		goto fail;
	}

	i2c_set_clientdata(client, mps2022);
	mps2022->dev = &client->dev;

	mps2022->regmap = devm_regmap_init_i2c(client, &mps2022_regmap);
	if (IS_ERR(mps2022->regmap)) {
		ret = PTR_ERR(mps2022->regmap);
		dev_err(&client->dev, "failed to allocate register map: %d\n",
			ret);
		goto fail;
	}

	if (!mps2022->dev->of_node) {
		ret = -EINVAL;
		dev_err(&client->dev, "no of_node found: %d\n", ret);
		goto fail;
	}

	mps2022->config = of_get_mps2022_config(mps2022);
	if (IS_ERR(mps2022->config)) {
		ret = PTR_ERR(mps2022->config);
		goto fail;
	}

	if (!regulator_is_enabled(mps2022->config->vin)) {
		ret = regulator_enable(mps2022->config->vin);
		if (ret)
			goto fail;
	}

	if (!regulator_is_enabled(mps2022->config->vdd))
		ret = regulator_enable(mps2022->config->vdd);

	/* prepare IRQ */
	mps2022->irq_thread = &mps2022_irq_thread;
	mps2022->irqflags = IRQF_ONESHOT;

#ifdef CONFIG_DIAG_CLASS
	init_waitqueue_head(&mps2022->adc_queue);
	mps2022->adc_done = false;
	mps2022->diag_cdev.groups = mps2022_attr_groups;
	mps2022->diag_cdev.get_diag_status = mps2022_sysfs_get_diag_status;
	ret = devm_of_diag_classdev_register(mps2022->dev,
						mps2022->dev->of_node,
						&mps2022->diag_cdev);
	if (ret)
		goto fail;

	mutex_init(&mps2022->diag_lock);
#endif /* CONFIG_DIAG_CLASS */

	res = devm_kzalloc(&client->dev, sizeof(struct resource), GFP_KERNEL);
	if (!res) {
		dev_err(mps2022->dev, "fail to request IRQ resource!!!\n");
		ret = -ENOMEM;
		goto fail;
	}

	/* if IRQ well defined in DT, then proceed IRQ configuration */
	if (mps2022->irq_thread && client->irq) {
		of_irq_to_resource(client->dev.of_node, 0, res);
		ret = devm_request_threaded_irq(mps2022->dev,
						client->irq, NULL,
						mps2022->irq_thread,
						mps2022->irqflags |res->flags,
						client->name,
						i2c_get_clientdata(client));
		if (ret) {
			dev_err(mps2022->dev, "fail to request IRQ\n");
			goto fail;
		}
		dev_info(mps2022->dev, "IRQ setup done\n");
	} else {
		dev_info(mps2022->dev, "IRQ setup not done\n");
	}

fail:
	return ret;
}

static int mps2022_remove(struct i2c_client *client)
{
	struct mps2022_data *mps2022 = client->dev.driver_data;
	int i;

	for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
		if (mps2022->config->outputs[i].exist) {
			if (mps2022_is_enabled(
					mps2022->config->outputs[i].dev))
				mps2022_disable(
					mps2022->config->outputs[i].dev);
		}
	}

#ifdef CONFIG_DIAG_CLASS
	mutex_destroy(&mps2022->diag_lock);
#endif /* CONFIG_DIAG_CLASS */

	return 0;
}

static const struct of_device_id mps2022_dt_ids[] = {
	{ .compatible = "mps,mps2022" },
	{},
};
MODULE_DEVICE_TABLE(of, mps2022_dt_ids);

static const struct i2c_device_id mps2022_i2c_ids[] = {
	{ "mps2022", 0 },
	{ },
};
MODULE_DEVICE_TABLE(i2c, mps2022_i2c_ids);

static struct i2c_driver mps2022_driver = {
	.driver		= {
		.name = KBUILD_MODNAME,
		.owner = THIS_MODULE,
		.of_match_table = mps2022_dt_ids,
	},
	.probe		= mps2022_probe,
	.remove 	= mps2022_remove,
	.id_table	= mps2022_i2c_ids,
};
module_i2c_driver(mps2022_driver);

MODULE_DESCRIPTION("mps Camera Power Protectors driver");
MODULE_AUTHOR("zhenggp");
MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值