139b1772aSDaniel Ribeiro /* 239b1772aSDaniel Ribeiro * PCAP2 Regulator Driver 339b1772aSDaniel Ribeiro * 439b1772aSDaniel Ribeiro * Copyright (c) 2009 Daniel Ribeiro <drwyrm@gmail.com> 539b1772aSDaniel Ribeiro * 639b1772aSDaniel Ribeiro * This program is free software; you can redistribute it and/or modify it 739b1772aSDaniel Ribeiro * under the terms of the GNU General Public License as published by the 839b1772aSDaniel Ribeiro * Free Software Foundation; either version 2 of the License, or (at your 939b1772aSDaniel Ribeiro * option) any later version. 1039b1772aSDaniel Ribeiro */ 1139b1772aSDaniel Ribeiro 1239b1772aSDaniel Ribeiro #include <linux/kernel.h> 1339b1772aSDaniel Ribeiro #include <linux/module.h> 1439b1772aSDaniel Ribeiro #include <linux/init.h> 1539b1772aSDaniel Ribeiro #include <linux/err.h> 1639b1772aSDaniel Ribeiro #include <linux/platform_device.h> 1739b1772aSDaniel Ribeiro #include <linux/regulator/driver.h> 1839b1772aSDaniel Ribeiro #include <linux/regulator/machine.h> 1939b1772aSDaniel Ribeiro #include <linux/mfd/ezx-pcap.h> 2039b1772aSDaniel Ribeiro 2139b1772aSDaniel Ribeiro static const u16 V1_table[] = { 2239b1772aSDaniel Ribeiro 2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275, 2339b1772aSDaniel Ribeiro }; 2439b1772aSDaniel Ribeiro 2539b1772aSDaniel Ribeiro static const u16 V2_table[] = { 2639b1772aSDaniel Ribeiro 2500, 2775, 2739b1772aSDaniel Ribeiro }; 2839b1772aSDaniel Ribeiro 2939b1772aSDaniel Ribeiro static const u16 V3_table[] = { 3039b1772aSDaniel Ribeiro 1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275, 3139b1772aSDaniel Ribeiro }; 3239b1772aSDaniel Ribeiro 3339b1772aSDaniel Ribeiro static const u16 V4_table[] = { 3439b1772aSDaniel Ribeiro 1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775, 3539b1772aSDaniel Ribeiro }; 3639b1772aSDaniel Ribeiro 3739b1772aSDaniel Ribeiro static const u16 V5_table[] = { 3839b1772aSDaniel Ribeiro 1875, 2275, 2475, 2775, 3939b1772aSDaniel Ribeiro }; 4039b1772aSDaniel Ribeiro 4139b1772aSDaniel Ribeiro static const u16 V6_table[] = { 4239b1772aSDaniel Ribeiro 2475, 2775, 4339b1772aSDaniel Ribeiro }; 4439b1772aSDaniel Ribeiro 4539b1772aSDaniel Ribeiro static const u16 V7_table[] = { 4639b1772aSDaniel Ribeiro 1875, 2775, 4739b1772aSDaniel Ribeiro }; 4839b1772aSDaniel Ribeiro 4939b1772aSDaniel Ribeiro #define V8_table V4_table 5039b1772aSDaniel Ribeiro 5139b1772aSDaniel Ribeiro static const u16 V9_table[] = { 5239b1772aSDaniel Ribeiro 1575, 1875, 2475, 2775, 5339b1772aSDaniel Ribeiro }; 5439b1772aSDaniel Ribeiro 5539b1772aSDaniel Ribeiro static const u16 V10_table[] = { 5639b1772aSDaniel Ribeiro 5000, 5739b1772aSDaniel Ribeiro }; 5839b1772aSDaniel Ribeiro 5939b1772aSDaniel Ribeiro static const u16 VAUX1_table[] = { 6039b1772aSDaniel Ribeiro 1875, 2475, 2775, 3000, 6139b1772aSDaniel Ribeiro }; 6239b1772aSDaniel Ribeiro 6339b1772aSDaniel Ribeiro #define VAUX2_table VAUX1_table 6439b1772aSDaniel Ribeiro 6539b1772aSDaniel Ribeiro static const u16 VAUX3_table[] = { 6639b1772aSDaniel Ribeiro 1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000, 6739b1772aSDaniel Ribeiro 2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600, 6839b1772aSDaniel Ribeiro }; 6939b1772aSDaniel Ribeiro 7039b1772aSDaniel Ribeiro static const u16 VAUX4_table[] = { 7139b1772aSDaniel Ribeiro 1800, 1800, 3000, 5000, 7239b1772aSDaniel Ribeiro }; 7339b1772aSDaniel Ribeiro 7439b1772aSDaniel Ribeiro static const u16 VSIM_table[] = { 7539b1772aSDaniel Ribeiro 1875, 3000, 7639b1772aSDaniel Ribeiro }; 7739b1772aSDaniel Ribeiro 7839b1772aSDaniel Ribeiro static const u16 VSIM2_table[] = { 7939b1772aSDaniel Ribeiro 1875, 8039b1772aSDaniel Ribeiro }; 8139b1772aSDaniel Ribeiro 8239b1772aSDaniel Ribeiro static const u16 VVIB_table[] = { 8339b1772aSDaniel Ribeiro 1300, 1800, 2000, 3000, 8439b1772aSDaniel Ribeiro }; 8539b1772aSDaniel Ribeiro 8639b1772aSDaniel Ribeiro static const u16 SW1_table[] = { 8739b1772aSDaniel Ribeiro 900, 950, 1000, 1050, 1100, 1150, 1200, 1250, 8839b1772aSDaniel Ribeiro 1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250, 8939b1772aSDaniel Ribeiro }; 9039b1772aSDaniel Ribeiro 9139b1772aSDaniel Ribeiro #define SW2_table SW1_table 9239b1772aSDaniel Ribeiro 9339b1772aSDaniel Ribeiro static const u16 SW3_table[] = { 9439b1772aSDaniel Ribeiro 4000, 4500, 5000, 5500, 9539b1772aSDaniel Ribeiro }; 9639b1772aSDaniel Ribeiro 9739b1772aSDaniel Ribeiro struct pcap_regulator { 9839b1772aSDaniel Ribeiro const u8 reg; 9939b1772aSDaniel Ribeiro const u8 en; 10039b1772aSDaniel Ribeiro const u8 index; 10139b1772aSDaniel Ribeiro const u8 stby; 10239b1772aSDaniel Ribeiro const u8 lowpwr; 10339b1772aSDaniel Ribeiro const u8 n_voltages; 10439b1772aSDaniel Ribeiro const u16 *voltage_table; 10539b1772aSDaniel Ribeiro }; 10639b1772aSDaniel Ribeiro 10739b1772aSDaniel Ribeiro #define NA 0xff 10839b1772aSDaniel Ribeiro 10939b1772aSDaniel Ribeiro #define VREG_INFO(_vreg, _reg, _en, _index, _stby, _lowpwr) \ 11039b1772aSDaniel Ribeiro [_vreg] = { \ 11139b1772aSDaniel Ribeiro .reg = _reg, \ 11239b1772aSDaniel Ribeiro .en = _en, \ 11339b1772aSDaniel Ribeiro .index = _index, \ 11439b1772aSDaniel Ribeiro .stby = _stby, \ 11539b1772aSDaniel Ribeiro .lowpwr = _lowpwr, \ 11639b1772aSDaniel Ribeiro .n_voltages = ARRAY_SIZE(_vreg##_table), \ 11739b1772aSDaniel Ribeiro .voltage_table = _vreg##_table, \ 11839b1772aSDaniel Ribeiro } 11939b1772aSDaniel Ribeiro 12039b1772aSDaniel Ribeiro static struct pcap_regulator vreg_table[] = { 12139b1772aSDaniel Ribeiro VREG_INFO(V1, PCAP_REG_VREG1, 1, 2, 18, 0), 12239b1772aSDaniel Ribeiro VREG_INFO(V2, PCAP_REG_VREG1, 5, 6, 19, 22), 12339b1772aSDaniel Ribeiro VREG_INFO(V3, PCAP_REG_VREG1, 7, 8, 20, 23), 12439b1772aSDaniel Ribeiro VREG_INFO(V4, PCAP_REG_VREG1, 11, 12, 21, 24), 12539b1772aSDaniel Ribeiro /* V5 STBY and LOWPWR are on PCAP_REG_VREG2 */ 12639b1772aSDaniel Ribeiro VREG_INFO(V5, PCAP_REG_VREG1, 15, 16, 12, 19), 12739b1772aSDaniel Ribeiro 12839b1772aSDaniel Ribeiro VREG_INFO(V6, PCAP_REG_VREG2, 1, 2, 14, 20), 12939b1772aSDaniel Ribeiro VREG_INFO(V7, PCAP_REG_VREG2, 3, 4, 15, 21), 13039b1772aSDaniel Ribeiro VREG_INFO(V8, PCAP_REG_VREG2, 5, 6, 16, 22), 13139b1772aSDaniel Ribeiro VREG_INFO(V9, PCAP_REG_VREG2, 9, 10, 17, 23), 13239b1772aSDaniel Ribeiro VREG_INFO(V10, PCAP_REG_VREG2, 10, NA, 18, 24), 13339b1772aSDaniel Ribeiro 13439b1772aSDaniel Ribeiro VREG_INFO(VAUX1, PCAP_REG_AUXVREG, 1, 2, 22, 23), 13539b1772aSDaniel Ribeiro /* VAUX2 ... VSIM2 STBY and LOWPWR are on PCAP_REG_LOWPWR */ 13639b1772aSDaniel Ribeiro VREG_INFO(VAUX2, PCAP_REG_AUXVREG, 4, 5, 0, 1), 13739b1772aSDaniel Ribeiro VREG_INFO(VAUX3, PCAP_REG_AUXVREG, 7, 8, 2, 3), 13839b1772aSDaniel Ribeiro VREG_INFO(VAUX4, PCAP_REG_AUXVREG, 12, 13, 4, 5), 13939b1772aSDaniel Ribeiro VREG_INFO(VSIM, PCAP_REG_AUXVREG, 17, 18, NA, 6), 14039b1772aSDaniel Ribeiro VREG_INFO(VSIM2, PCAP_REG_AUXVREG, 16, NA, NA, 7), 14139b1772aSDaniel Ribeiro VREG_INFO(VVIB, PCAP_REG_AUXVREG, 19, 20, NA, NA), 14239b1772aSDaniel Ribeiro 14339b1772aSDaniel Ribeiro VREG_INFO(SW1, PCAP_REG_SWCTRL, 1, 2, NA, NA), 14439b1772aSDaniel Ribeiro VREG_INFO(SW2, PCAP_REG_SWCTRL, 6, 7, NA, NA), 14539b1772aSDaniel Ribeiro /* SW3 STBY is on PCAP_REG_AUXVREG */ 14639b1772aSDaniel Ribeiro VREG_INFO(SW3, PCAP_REG_SWCTRL, 11, 12, 24, NA), 14739b1772aSDaniel Ribeiro 14839b1772aSDaniel Ribeiro /* SWxS used to control SWx voltage on standby */ 14939b1772aSDaniel Ribeiro /* VREG_INFO(SW1S, PCAP_REG_LOWPWR, NA, 12, NA, NA), 15039b1772aSDaniel Ribeiro VREG_INFO(SW2S, PCAP_REG_LOWPWR, NA, 20, NA, NA), */ 15139b1772aSDaniel Ribeiro }; 15239b1772aSDaniel Ribeiro 153d5ec9635SAxel Lin static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev, 154d5ec9635SAxel Lin unsigned selector) 15539b1772aSDaniel Ribeiro { 15639b1772aSDaniel Ribeiro struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; 15739b1772aSDaniel Ribeiro void *pcap = rdev_get_drvdata(rdev); 15839b1772aSDaniel Ribeiro 15939b1772aSDaniel Ribeiro /* the regulator doesn't support voltage switching */ 16039b1772aSDaniel Ribeiro if (vreg->n_voltages == 1) 16139b1772aSDaniel Ribeiro return -EINVAL; 16239b1772aSDaniel Ribeiro 16339b1772aSDaniel Ribeiro return ezx_pcap_set_bits(pcap, vreg->reg, 16439b1772aSDaniel Ribeiro (vreg->n_voltages - 1) << vreg->index, 165d5ec9635SAxel Lin selector << vreg->index); 16639b1772aSDaniel Ribeiro } 16739b1772aSDaniel Ribeiro 1683cbff37eSAxel Lin static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev) 16939b1772aSDaniel Ribeiro { 17039b1772aSDaniel Ribeiro struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; 17139b1772aSDaniel Ribeiro void *pcap = rdev_get_drvdata(rdev); 17239b1772aSDaniel Ribeiro u32 tmp; 17339b1772aSDaniel Ribeiro 17439b1772aSDaniel Ribeiro if (vreg->n_voltages == 1) 1753cbff37eSAxel Lin return 0; 17639b1772aSDaniel Ribeiro 17739b1772aSDaniel Ribeiro ezx_pcap_read(pcap, vreg->reg, &tmp); 17839b1772aSDaniel Ribeiro tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1)); 1793cbff37eSAxel Lin return tmp; 18039b1772aSDaniel Ribeiro } 18139b1772aSDaniel Ribeiro 18239b1772aSDaniel Ribeiro static int pcap_regulator_enable(struct regulator_dev *rdev) 18339b1772aSDaniel Ribeiro { 18439b1772aSDaniel Ribeiro struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; 18539b1772aSDaniel Ribeiro void *pcap = rdev_get_drvdata(rdev); 18639b1772aSDaniel Ribeiro 18739b1772aSDaniel Ribeiro if (vreg->en == NA) 18839b1772aSDaniel Ribeiro return -EINVAL; 18939b1772aSDaniel Ribeiro 19039b1772aSDaniel Ribeiro return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 1 << vreg->en); 19139b1772aSDaniel Ribeiro } 19239b1772aSDaniel Ribeiro 19339b1772aSDaniel Ribeiro static int pcap_regulator_disable(struct regulator_dev *rdev) 19439b1772aSDaniel Ribeiro { 19539b1772aSDaniel Ribeiro struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; 19639b1772aSDaniel Ribeiro void *pcap = rdev_get_drvdata(rdev); 19739b1772aSDaniel Ribeiro 19839b1772aSDaniel Ribeiro if (vreg->en == NA) 19939b1772aSDaniel Ribeiro return -EINVAL; 20039b1772aSDaniel Ribeiro 20139b1772aSDaniel Ribeiro return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 0); 20239b1772aSDaniel Ribeiro } 20339b1772aSDaniel Ribeiro 20439b1772aSDaniel Ribeiro static int pcap_regulator_is_enabled(struct regulator_dev *rdev) 20539b1772aSDaniel Ribeiro { 20639b1772aSDaniel Ribeiro struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; 20739b1772aSDaniel Ribeiro void *pcap = rdev_get_drvdata(rdev); 20839b1772aSDaniel Ribeiro u32 tmp; 20939b1772aSDaniel Ribeiro 21039b1772aSDaniel Ribeiro if (vreg->en == NA) 21139b1772aSDaniel Ribeiro return -EINVAL; 21239b1772aSDaniel Ribeiro 21339b1772aSDaniel Ribeiro ezx_pcap_read(pcap, vreg->reg, &tmp); 21439b1772aSDaniel Ribeiro return (tmp >> vreg->en) & 1; 21539b1772aSDaniel Ribeiro } 21639b1772aSDaniel Ribeiro 21739b1772aSDaniel Ribeiro static int pcap_regulator_list_voltage(struct regulator_dev *rdev, 21839b1772aSDaniel Ribeiro unsigned int index) 21939b1772aSDaniel Ribeiro { 22039b1772aSDaniel Ribeiro struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; 22139b1772aSDaniel Ribeiro 22239b1772aSDaniel Ribeiro return vreg->voltage_table[index] * 1000; 22339b1772aSDaniel Ribeiro } 22439b1772aSDaniel Ribeiro 22539b1772aSDaniel Ribeiro static struct regulator_ops pcap_regulator_ops = { 22639b1772aSDaniel Ribeiro .list_voltage = pcap_regulator_list_voltage, 227d5ec9635SAxel Lin .set_voltage_sel = pcap_regulator_set_voltage_sel, 2283cbff37eSAxel Lin .get_voltage_sel = pcap_regulator_get_voltage_sel, 22939b1772aSDaniel Ribeiro .enable = pcap_regulator_enable, 23039b1772aSDaniel Ribeiro .disable = pcap_regulator_disable, 23139b1772aSDaniel Ribeiro .is_enabled = pcap_regulator_is_enabled, 23239b1772aSDaniel Ribeiro }; 23339b1772aSDaniel Ribeiro 23439b1772aSDaniel Ribeiro #define VREG(_vreg) \ 23539b1772aSDaniel Ribeiro [_vreg] = { \ 23639b1772aSDaniel Ribeiro .name = #_vreg, \ 23739b1772aSDaniel Ribeiro .id = _vreg, \ 23839b1772aSDaniel Ribeiro .n_voltages = ARRAY_SIZE(_vreg##_table), \ 23939b1772aSDaniel Ribeiro .ops = &pcap_regulator_ops, \ 24039b1772aSDaniel Ribeiro .type = REGULATOR_VOLTAGE, \ 24139b1772aSDaniel Ribeiro .owner = THIS_MODULE, \ 24239b1772aSDaniel Ribeiro } 24339b1772aSDaniel Ribeiro 2440d2fbc51SAxel Lin static const struct regulator_desc pcap_regulators[] = { 24539b1772aSDaniel Ribeiro VREG(V1), VREG(V2), VREG(V3), VREG(V4), VREG(V5), VREG(V6), VREG(V7), 24639b1772aSDaniel Ribeiro VREG(V8), VREG(V9), VREG(V10), VREG(VAUX1), VREG(VAUX2), VREG(VAUX3), 24739b1772aSDaniel Ribeiro VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2), 24839b1772aSDaniel Ribeiro }; 24939b1772aSDaniel Ribeiro 25039b1772aSDaniel Ribeiro static int __devinit pcap_regulator_probe(struct platform_device *pdev) 25139b1772aSDaniel Ribeiro { 25239b1772aSDaniel Ribeiro struct regulator_dev *rdev; 25370fde5cbSAntonio Ospite void *pcap = dev_get_drvdata(pdev->dev.parent); 254c172708dSMark Brown struct regulator_config config = { }; 25539b1772aSDaniel Ribeiro 256c172708dSMark Brown config.dev = &pdev->dev; 257c172708dSMark Brown config.init_data = pdev->dev.platform_data; 258c172708dSMark Brown config.driver_data = pcap; 259c172708dSMark Brown 260c172708dSMark Brown rdev = regulator_register(&pcap_regulators[pdev->id], &config); 26139b1772aSDaniel Ribeiro if (IS_ERR(rdev)) 26239b1772aSDaniel Ribeiro return PTR_ERR(rdev); 26339b1772aSDaniel Ribeiro 26439b1772aSDaniel Ribeiro platform_set_drvdata(pdev, rdev); 26539b1772aSDaniel Ribeiro 26639b1772aSDaniel Ribeiro return 0; 26739b1772aSDaniel Ribeiro } 26839b1772aSDaniel Ribeiro 26939b1772aSDaniel Ribeiro static int __devexit pcap_regulator_remove(struct platform_device *pdev) 27039b1772aSDaniel Ribeiro { 27139b1772aSDaniel Ribeiro struct regulator_dev *rdev = platform_get_drvdata(pdev); 27239b1772aSDaniel Ribeiro 27339b1772aSDaniel Ribeiro regulator_unregister(rdev); 2746a74857dSDmitry Torokhov platform_set_drvdata(pdev, NULL); 27539b1772aSDaniel Ribeiro 27639b1772aSDaniel Ribeiro return 0; 27739b1772aSDaniel Ribeiro } 27839b1772aSDaniel Ribeiro 27939b1772aSDaniel Ribeiro static struct platform_driver pcap_regulator_driver = { 28039b1772aSDaniel Ribeiro .driver = { 28139b1772aSDaniel Ribeiro .name = "pcap-regulator", 2826a74857dSDmitry Torokhov .owner = THIS_MODULE, 28339b1772aSDaniel Ribeiro }, 28439b1772aSDaniel Ribeiro .probe = pcap_regulator_probe, 28539b1772aSDaniel Ribeiro .remove = __devexit_p(pcap_regulator_remove), 28639b1772aSDaniel Ribeiro }; 28739b1772aSDaniel Ribeiro 28839b1772aSDaniel Ribeiro static int __init pcap_regulator_init(void) 28939b1772aSDaniel Ribeiro { 29039b1772aSDaniel Ribeiro return platform_driver_register(&pcap_regulator_driver); 29139b1772aSDaniel Ribeiro } 29239b1772aSDaniel Ribeiro 29339b1772aSDaniel Ribeiro static void __exit pcap_regulator_exit(void) 29439b1772aSDaniel Ribeiro { 29539b1772aSDaniel Ribeiro platform_driver_unregister(&pcap_regulator_driver); 29639b1772aSDaniel Ribeiro } 29739b1772aSDaniel Ribeiro 298e397e7edSAntonio Ospite subsys_initcall(pcap_regulator_init); 29939b1772aSDaniel Ribeiro module_exit(pcap_regulator_exit); 30039b1772aSDaniel Ribeiro 30139b1772aSDaniel Ribeiro MODULE_AUTHOR("Daniel Ribeiro <drwyrm@gmail.com>"); 30239b1772aSDaniel Ribeiro MODULE_DESCRIPTION("PCAP2 Regulator Driver"); 30339b1772aSDaniel Ribeiro MODULE_LICENSE("GPL"); 304