cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tps65218.c (8741B)


      1/*
      2 * Driver for TPS65218 Integrated power management chipsets
      3 *
      4 * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/
      5 *
      6 * This program is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU General Public License version 2 as
      8 * published by the Free Software Foundation.
      9 *
     10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     11 * kind, whether expressed or implied; without even the implied warranty
     12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License version 2 for more details.
     14 */
     15
     16#include <linux/kernel.h>
     17#include <linux/device.h>
     18#include <linux/module.h>
     19#include <linux/platform_device.h>
     20#include <linux/init.h>
     21#include <linux/i2c.h>
     22#include <linux/slab.h>
     23#include <linux/regmap.h>
     24#include <linux/err.h>
     25#include <linux/of.h>
     26#include <linux/of_device.h>
     27#include <linux/irq.h>
     28#include <linux/interrupt.h>
     29#include <linux/mutex.h>
     30
     31#include <linux/mfd/core.h>
     32#include <linux/mfd/tps65218.h>
     33
     34#define TPS65218_PASSWORD_REGS_UNLOCK   0x7D
     35
     36static const struct mfd_cell tps65218_cells[] = {
     37	{
     38		.name = "tps65218-pwrbutton",
     39		.of_compatible = "ti,tps65218-pwrbutton",
     40	},
     41	{
     42		.name = "tps65218-gpio",
     43		.of_compatible = "ti,tps65218-gpio",
     44	},
     45	{ .name = "tps65218-regulator", },
     46};
     47
     48/**
     49 * tps65218_reg_write: Write a single tps65218 register.
     50 *
     51 * @tps: Device to write to.
     52 * @reg: Register to write to.
     53 * @val: Value to write.
     54 * @level: Password protected level
     55 */
     56int tps65218_reg_write(struct tps65218 *tps, unsigned int reg,
     57			unsigned int val, unsigned int level)
     58{
     59	int ret;
     60	unsigned int xor_reg_val;
     61
     62	switch (level) {
     63	case TPS65218_PROTECT_NONE:
     64		return regmap_write(tps->regmap, reg, val);
     65	case TPS65218_PROTECT_L1:
     66		xor_reg_val = reg ^ TPS65218_PASSWORD_REGS_UNLOCK;
     67		ret = regmap_write(tps->regmap, TPS65218_REG_PASSWORD,
     68							xor_reg_val);
     69		if (ret < 0)
     70			return ret;
     71
     72		return regmap_write(tps->regmap, reg, val);
     73	default:
     74		return -EINVAL;
     75	}
     76}
     77EXPORT_SYMBOL_GPL(tps65218_reg_write);
     78
     79/**
     80 * tps65218_update_bits: Modify bits w.r.t mask, val and level.
     81 *
     82 * @tps: Device to write to.
     83 * @reg: Register to read-write to.
     84 * @mask: Mask.
     85 * @val: Value to write.
     86 * @level: Password protected level
     87 */
     88static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg,
     89		unsigned int mask, unsigned int val, unsigned int level)
     90{
     91	int ret;
     92	unsigned int data;
     93
     94	ret = regmap_read(tps->regmap, reg, &data);
     95	if (ret) {
     96		dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
     97		return ret;
     98	}
     99
    100	data &= ~mask;
    101	data |= val & mask;
    102
    103	mutex_lock(&tps->tps_lock);
    104	ret = tps65218_reg_write(tps, reg, data, level);
    105	if (ret)
    106		dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
    107	mutex_unlock(&tps->tps_lock);
    108
    109	return ret;
    110}
    111
    112int tps65218_set_bits(struct tps65218 *tps, unsigned int reg,
    113		unsigned int mask, unsigned int val, unsigned int level)
    114{
    115	return tps65218_update_bits(tps, reg, mask, val, level);
    116}
    117EXPORT_SYMBOL_GPL(tps65218_set_bits);
    118
    119int tps65218_clear_bits(struct tps65218 *tps, unsigned int reg,
    120		unsigned int mask, unsigned int level)
    121{
    122	return tps65218_update_bits(tps, reg, mask, 0, level);
    123}
    124EXPORT_SYMBOL_GPL(tps65218_clear_bits);
    125
    126static const struct regmap_range tps65218_yes_ranges[] = {
    127	regmap_reg_range(TPS65218_REG_INT1, TPS65218_REG_INT2),
    128	regmap_reg_range(TPS65218_REG_STATUS, TPS65218_REG_STATUS),
    129};
    130
    131static const struct regmap_access_table tps65218_volatile_table = {
    132	.yes_ranges = tps65218_yes_ranges,
    133	.n_yes_ranges = ARRAY_SIZE(tps65218_yes_ranges),
    134};
    135
    136static const struct regmap_config tps65218_regmap_config = {
    137	.reg_bits = 8,
    138	.val_bits = 8,
    139	.cache_type = REGCACHE_RBTREE,
    140	.volatile_table = &tps65218_volatile_table,
    141};
    142
    143static const struct regmap_irq tps65218_irqs[] = {
    144	/* INT1 IRQs */
    145	[TPS65218_PRGC_IRQ] = {
    146		.mask = TPS65218_INT1_PRGC,
    147	},
    148	[TPS65218_CC_AQC_IRQ] = {
    149		.mask = TPS65218_INT1_CC_AQC,
    150	},
    151	[TPS65218_HOT_IRQ] = {
    152		.mask = TPS65218_INT1_HOT,
    153	},
    154	[TPS65218_PB_IRQ] = {
    155		.mask = TPS65218_INT1_PB,
    156	},
    157	[TPS65218_AC_IRQ] = {
    158		.mask = TPS65218_INT1_AC,
    159	},
    160	[TPS65218_VPRG_IRQ] = {
    161		.mask = TPS65218_INT1_VPRG,
    162	},
    163	[TPS65218_INVALID1_IRQ] = {
    164	},
    165	[TPS65218_INVALID2_IRQ] = {
    166	},
    167	/* INT2 IRQs*/
    168	[TPS65218_LS1_I_IRQ] = {
    169		.mask = TPS65218_INT2_LS1_I,
    170		.reg_offset = 1,
    171	},
    172	[TPS65218_LS2_I_IRQ] = {
    173		.mask = TPS65218_INT2_LS2_I,
    174		.reg_offset = 1,
    175	},
    176	[TPS65218_LS3_I_IRQ] = {
    177		.mask = TPS65218_INT2_LS3_I,
    178		.reg_offset = 1,
    179	},
    180	[TPS65218_LS1_F_IRQ] = {
    181		.mask = TPS65218_INT2_LS1_F,
    182		.reg_offset = 1,
    183	},
    184	[TPS65218_LS2_F_IRQ] = {
    185		.mask = TPS65218_INT2_LS2_F,
    186		.reg_offset = 1,
    187	},
    188	[TPS65218_LS3_F_IRQ] = {
    189		.mask = TPS65218_INT2_LS3_F,
    190		.reg_offset = 1,
    191	},
    192	[TPS65218_INVALID3_IRQ] = {
    193	},
    194	[TPS65218_INVALID4_IRQ] = {
    195	},
    196};
    197
    198static struct regmap_irq_chip tps65218_irq_chip = {
    199	.name = "tps65218",
    200	.irqs = tps65218_irqs,
    201	.num_irqs = ARRAY_SIZE(tps65218_irqs),
    202
    203	.num_regs = 2,
    204	.mask_base = TPS65218_REG_INT_MASK1,
    205	.status_base = TPS65218_REG_INT1,
    206};
    207
    208static const struct of_device_id of_tps65218_match_table[] = {
    209	{ .compatible = "ti,tps65218", },
    210	{}
    211};
    212MODULE_DEVICE_TABLE(of, of_tps65218_match_table);
    213
    214static int tps65218_voltage_set_strict(struct tps65218 *tps)
    215{
    216	u32 strict;
    217
    218	if (of_property_read_u32(tps->dev->of_node,
    219				 "ti,strict-supply-voltage-supervision",
    220				 &strict))
    221		return 0;
    222
    223	if (strict != 0 && strict != 1) {
    224		dev_err(tps->dev,
    225			"Invalid ti,strict-supply-voltage-supervision value\n");
    226		return -EINVAL;
    227	}
    228
    229	tps65218_update_bits(tps, TPS65218_REG_CONFIG1,
    230			     TPS65218_CONFIG1_STRICT,
    231			     strict ? TPS65218_CONFIG1_STRICT : 0,
    232			     TPS65218_PROTECT_L1);
    233	return 0;
    234}
    235
    236static int tps65218_voltage_set_uv_hyst(struct tps65218 *tps)
    237{
    238	u32 hyst;
    239
    240	if (of_property_read_u32(tps->dev->of_node,
    241				 "ti,under-voltage-hyst-microvolt", &hyst))
    242		return 0;
    243
    244	if (hyst != 400000 && hyst != 200000) {
    245		dev_err(tps->dev,
    246			"Invalid ti,under-voltage-hyst-microvolt value\n");
    247		return -EINVAL;
    248	}
    249
    250	tps65218_update_bits(tps, TPS65218_REG_CONFIG2,
    251			     TPS65218_CONFIG2_UVLOHYS,
    252			     hyst == 400000 ? TPS65218_CONFIG2_UVLOHYS : 0,
    253			     TPS65218_PROTECT_L1);
    254	return 0;
    255}
    256
    257static int tps65218_voltage_set_uvlo(struct tps65218 *tps)
    258{
    259	u32 uvlo;
    260	int uvloval;
    261
    262	if (of_property_read_u32(tps->dev->of_node,
    263				 "ti,under-voltage-limit-microvolt", &uvlo))
    264		return 0;
    265
    266	switch (uvlo) {
    267	case 2750000:
    268		uvloval = TPS65218_CONFIG1_UVLO_2750000;
    269		break;
    270	case 2950000:
    271		uvloval = TPS65218_CONFIG1_UVLO_2950000;
    272		break;
    273	case 3250000:
    274		uvloval = TPS65218_CONFIG1_UVLO_3250000;
    275		break;
    276	case 3350000:
    277		uvloval = TPS65218_CONFIG1_UVLO_3350000;
    278		break;
    279	default:
    280		dev_err(tps->dev,
    281			"Invalid ti,under-voltage-limit-microvolt value\n");
    282		return -EINVAL;
    283	}
    284
    285	tps65218_update_bits(tps, TPS65218_REG_CONFIG1,
    286			     TPS65218_CONFIG1_UVLO_MASK, uvloval,
    287			     TPS65218_PROTECT_L1);
    288	return 0;
    289}
    290
    291static int tps65218_probe(struct i2c_client *client,
    292				const struct i2c_device_id *ids)
    293{
    294	struct tps65218 *tps;
    295	int ret;
    296	unsigned int chipid;
    297
    298	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
    299	if (!tps)
    300		return -ENOMEM;
    301
    302	i2c_set_clientdata(client, tps);
    303	tps->dev = &client->dev;
    304	tps->irq = client->irq;
    305	tps->regmap = devm_regmap_init_i2c(client, &tps65218_regmap_config);
    306	if (IS_ERR(tps->regmap)) {
    307		ret = PTR_ERR(tps->regmap);
    308		dev_err(tps->dev, "Failed to allocate register map: %d\n",
    309			ret);
    310		return ret;
    311	}
    312
    313	mutex_init(&tps->tps_lock);
    314
    315	ret = devm_regmap_add_irq_chip(&client->dev, tps->regmap, tps->irq,
    316				       IRQF_ONESHOT, 0, &tps65218_irq_chip,
    317				       &tps->irq_data);
    318	if (ret < 0)
    319		return ret;
    320
    321	ret = regmap_read(tps->regmap, TPS65218_REG_CHIPID, &chipid);
    322	if (ret) {
    323		dev_err(tps->dev, "Failed to read chipid: %d\n", ret);
    324		return ret;
    325	}
    326
    327	tps->rev = chipid & TPS65218_CHIPID_REV_MASK;
    328
    329	ret = tps65218_voltage_set_strict(tps);
    330	if (ret)
    331		return ret;
    332
    333	ret = tps65218_voltage_set_uvlo(tps);
    334	if (ret)
    335		return ret;
    336
    337	ret = tps65218_voltage_set_uv_hyst(tps);
    338	if (ret)
    339		return ret;
    340
    341	ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65218_cells,
    342			      ARRAY_SIZE(tps65218_cells), NULL, 0,
    343			      regmap_irq_get_domain(tps->irq_data));
    344
    345	return ret;
    346}
    347
    348static const struct i2c_device_id tps65218_id_table[] = {
    349	{ "tps65218", TPS65218 },
    350	{ },
    351};
    352MODULE_DEVICE_TABLE(i2c, tps65218_id_table);
    353
    354static struct i2c_driver tps65218_driver = {
    355	.driver		= {
    356		.name	= "tps65218",
    357		.of_match_table = of_tps65218_match_table,
    358	},
    359	.probe		= tps65218_probe,
    360	.id_table       = tps65218_id_table,
    361};
    362
    363module_i2c_driver(tps65218_driver);
    364
    365MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
    366MODULE_DESCRIPTION("TPS65218 chip family multi-function driver");
    367MODULE_LICENSE("GPL v2");