/* * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PFUZE_NUMREGS 128 #define PFUZE100_VOL_OFFSET 0 #define PFUZE100_STANDBY_OFFSET 1 #define PFUZE100_MODE_OFFSET 3 #define PFUZE100_CONF_OFFSET 4 #define PFUZE100_DEVICEID 0x0 #define PFUZE100_REVID 0x3 #define PFUZE100_FABID 0x4 #define PFUZE100_SW1ABVOL 0x20 #define PFUZE100_SW1CVOL 0x2e #define PFUZE100_SW2VOL 0x35 #define PFUZE100_SW3AVOL 0x3c #define PFUZE100_SW3BVOL 0x43 #define PFUZE100_SW4VOL 0x4a #define PFUZE100_SWBSTCON1 0x66 #define PFUZE100_VREFDDRCON 0x6a #define PFUZE100_VSNVSVOL 0x6b #define PFUZE100_VGEN1VOL 0x6c #define PFUZE100_VGEN2VOL 0x6d #define PFUZE100_VGEN3VOL 0x6e #define PFUZE100_VGEN4VOL 0x6f #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 }; struct pfuze_regulator { struct regulator_desc desc; unsigned char stby_reg; unsigned char stby_mask; }; struct pfuze_chip { int chip_id; struct regmap *regmap; struct device *dev; struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR]; }; static const int pfuze100_swbst[] = { 5000000, 5050000, 5100000, 5150000, }; static const int pfuze100_vsnvs[] = { 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, }; static const int pfuze3000_sw2lo[] = { 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, }; static const int pfuze3000_sw2hi[] = { 2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000, }; static const struct i2c_device_id pfuze_device_id[] = { {.name = "pfuze100", .driver_data = PFUZE100}, {.name = "pfuze200", .driver_data = PFUZE200}, {.name = "pfuze3000", .driver_data = PFUZE3000}, { } }; MODULE_DEVICE_TABLE(i2c, pfuze_device_id); static const struct of_device_id pfuze_dt_ids[] = { { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000}, { } }; MODULE_DEVICE_TABLE(of, pfuze_dt_ids); static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); unsigned int ramp_bits; int ret; if (id < PFUZE100_SWBST) { ramp_delay = 12500 / ramp_delay; ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3); ret = regmap_update_bits(pfuze100->regmap, rdev->desc->vsel_reg + 4, 0xc0, ramp_bits << 6); if (ret < 0) dev_err(pfuze100->dev, "ramp failed, err %d\n", ret); } else ret = -EACCES; return ret; } static struct regulator_ops pfuze100_ldo_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, }; static struct regulator_ops pfuze100_fixed_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_linear, }; static struct regulator_ops pfuze100_sw_regulator_ops = { .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_ramp_delay = pfuze100_set_ramp_delay, }; static struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, }; #define PFUZE100_FIXED_REG(_chip, _name, base, voltage) \ [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = 1, \ .ops = &pfuze100_fixed_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (voltage), \ .enable_reg = (base), \ .enable_mask = 0x10, \ }, \ } #define PFUZE100_SW_REG(_chip, _name, base, min, max, step) \ [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name,\ .n_voltages = ((max) - (min)) / (step) + 1, \ .ops = &pfuze100_sw_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (min), \ .uV_step = (step), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x3f, \ }, \ .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ .stby_mask = 0x3f, \ } #define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \ [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = ARRAY_SIZE(voltages), \ .ops = &pfuze100_swb_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .volt_table = voltages, \ .vsel_reg = (base), \ .vsel_mask = (mask), \ .enable_reg = (base), \ .enable_mask = 0x48,
/*
 * SDK7786 FPGA PCIe mux handling
 *
 * Copyright (C) 2010  Paul Mundt
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#define pr_fmt(fmt) "PCI: " fmt

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <mach/fpga.h>

/*
 * The SDK7786 FPGA supports mangling of most of the slots in some way or
 * another. Slots 3/4 are special in that only one can be supported at a
 * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4
 * (the horizontal edge connector) will disable slot 3 entirely.
 *
 * Misconfigurations can be detected through the FPGA via the slot
 * resistors to determine card presence. Hotplug remains unsupported.
 */
static unsigned int slot4en __initdata;

char *__init pcibios_setup(char *str)
{
	if (strcmp(str, "slot4en") == 0) {
		slot4en = 1;
		return NULL;
	}

	return str;
}

static int __init sdk7786_pci_init(void)
{
	u16 data = fpga_read_reg(PCIECR);

	/*
	 * Enable slot #4 if it's been specified on the command line.
	 *
	 * Optionally reroute if slot #4 has a card present while slot #3
	 * does not, regardless of command line value.
	 *
	 * Card presence is logically inverted.
	 */
	slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3));
	if (slot4en) {
		pr_info("Activating PCIe slot#4 (disabling slot#3)\n