250 lines
5.7 KiB
C
250 lines
5.7 KiB
C
/*
|
|
* Copyright (C) 2014 Sascha Hauer, Pengutronix
|
|
*
|
|
* 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.
|
|
*/
|
|
#define pr_fmt(fmt) "imx6sx-sdb: " fmt
|
|
|
|
#include <environment.h>
|
|
#include <partition.h>
|
|
#include <common.h>
|
|
#include <linux/sizes.h>
|
|
#include <gpio.h>
|
|
#include <init.h>
|
|
#include <io.h>
|
|
#include <mfd/imx6q-iomuxc-gpr.h>
|
|
#include <generated/mach-types.h>
|
|
#include <linux/clk.h>
|
|
#include <i2c/i2c.h>
|
|
|
|
#include <asm/armlinux.h>
|
|
|
|
#include <mach/devices-imx6.h>
|
|
#include <mach/imx6-regs.h>
|
|
#include <mach/iomux-mx6.h>
|
|
#include <mach/generic.h>
|
|
#include <mach/imx6.h>
|
|
#include <mach/bbu.h>
|
|
|
|
#define PFUZE100_DEVICEID 0x0
|
|
#define PFUZE100_REVID 0x3
|
|
#define PFUZE100_FABID 0x4
|
|
|
|
#define PFUZE100_SW1ABVOL 0x20
|
|
#define PFUZE100_SW1ABSTBY 0x21
|
|
#define PFUZE100_SW1ABCONF 0x24
|
|
#define PFUZE100_SW1CVOL 0x2e
|
|
#define PFUZE100_SW1CSTBY 0x2f
|
|
#define PFUZE100_SW1CCONF 0x32
|
|
#define PFUZE100_SW1ABC_SETP(x) ((x - 3000) / 250)
|
|
#define PFUZE100_VGEN5CTL 0x70
|
|
|
|
/* set all switches APS in normal and PFM mode in standby */
|
|
static int imx6sx_sdb_setup_pmic_mode(struct i2c_client *client, int chip)
|
|
{
|
|
unsigned char offset, i, switch_num, value;
|
|
|
|
if (!chip) {
|
|
/* pfuze100 */
|
|
switch_num = 6;
|
|
offset = 0x31;
|
|
} else {
|
|
/* pfuze200 */
|
|
switch_num = 4;
|
|
offset = 0x38;
|
|
}
|
|
|
|
value = 0xc;
|
|
if (i2c_write_reg(client, 0x23, &value, 1) < 0)
|
|
return -EIO;
|
|
|
|
for (i = 0; i < switch_num - 1; i++)
|
|
if (i2c_write_reg(client, offset + i * 7, &value, 1) < 0)
|
|
return -EIO;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int imx6sx_sdb_setup_pmic_voltages(void)
|
|
{
|
|
unsigned char value, rev_id = 0;
|
|
struct i2c_adapter *adapter = NULL;
|
|
struct i2c_client client;
|
|
int addr = -1, bus = 0;
|
|
|
|
if (!of_machine_is_compatible("fsl,imx6sx-sdb"))
|
|
return 0;
|
|
|
|
/* I2C2 bus (2-1 = 1 in barebox numbering) */
|
|
bus = 0;
|
|
|
|
/* PFUZE100 device address is 0x08 */
|
|
addr = 0x08;
|
|
|
|
adapter = i2c_get_adapter(bus);
|
|
if (!adapter)
|
|
return -ENODEV;
|
|
|
|
client.adapter = adapter;
|
|
client.addr = addr;
|
|
|
|
if (i2c_read_reg(&client, PFUZE100_DEVICEID, &value, 1) < 0)
|
|
goto err_out;
|
|
if (i2c_read_reg(&client, PFUZE100_REVID, &rev_id, 1) < 0)
|
|
goto err_out;
|
|
|
|
pr_info("Found PFUZE100! deviceid 0x%x, revid 0x%x\n", value, rev_id);
|
|
|
|
if (imx6sx_sdb_setup_pmic_mode(&client, value & 0xf))
|
|
goto err_out;
|
|
|
|
/* set SW1AB standby volatage 0.975V */
|
|
if (i2c_read_reg(&client, PFUZE100_SW1ABSTBY, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
value &= ~0x3f;
|
|
value |= PFUZE100_SW1ABC_SETP(9750);
|
|
if (i2c_write_reg(&client, PFUZE100_SW1ABSTBY, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
/* set SW1AB/VDDARM step ramp up time from 16us to 4us/25mV */
|
|
if (i2c_read_reg(&client, PFUZE100_SW1ABCONF, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
value &= ~0xc0;
|
|
value |= 0x40;
|
|
if (i2c_write_reg(&client, PFUZE100_SW1ABCONF, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
|
|
/* set SW1C standby volatage 0.975V */
|
|
if (i2c_read_reg(&client, PFUZE100_SW1CSTBY, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
value &= ~0x3f;
|
|
value |= PFUZE100_SW1ABC_SETP(9750);
|
|
if (i2c_write_reg(&client, PFUZE100_SW1CSTBY, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
|
|
/* set SW1C/VDDSOC step ramp up time to from 16us to 4us/25mV */
|
|
if (i2c_read_reg(&client, PFUZE100_SW1CCONF, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
value &= ~0xc0;
|
|
value |= 0x40;
|
|
if (i2c_write_reg(&client, PFUZE100_SW1CCONF, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
/* Enable power of VGEN5 3V3, needed for SD3 */
|
|
if (i2c_read_reg(&client, PFUZE100_VGEN5CTL, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
value &= ~0x1F;
|
|
value |= 0x1F;
|
|
if (i2c_write_reg(&client, PFUZE100_VGEN5CTL, &value, 1) < 0)
|
|
goto err_out;
|
|
|
|
return 0;
|
|
|
|
err_out:
|
|
pr_err("Setting up PMIC failed\n");
|
|
|
|
return -EIO;
|
|
}
|
|
fs_initcall(imx6sx_sdb_setup_pmic_voltages);
|
|
|
|
int ar8031_phy_fixup(struct phy_device *phydev)
|
|
{
|
|
/*
|
|
* Enable 1.8V(SEL_1P5_1P8_POS_REG) on
|
|
* Phy control debug reg 0
|
|
*/
|
|
phy_write(phydev, 0x1d, 0x1f);
|
|
phy_write(phydev, 0x1e, 0x8);
|
|
|
|
/* rgmii tx clock delay enable */
|
|
phy_write(phydev, 0x1d, 0x05);
|
|
phy_write(phydev, 0x1e, 0x100);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define PHY_ID_AR8031 0x004dd074
|
|
#define AR_PHY_ID_MASK 0xffffffff
|
|
|
|
static int imx6sx_sdb_setup_fec(void)
|
|
{
|
|
void __iomem *gprbase = (void *)MX6_IOMUXC_BASE_ADDR + 0x4000;
|
|
uint32_t val;
|
|
struct clk *clk;
|
|
|
|
phy_register_fixup_for_uid(PHY_ID_AR8031, AR_PHY_ID_MASK,
|
|
ar8031_phy_fixup);
|
|
|
|
/* Active high for ncp692 */
|
|
gpio_direction_output(IMX_GPIO_NR(4, 16), 1);
|
|
|
|
clk = clk_lookup("enet_ptp_25m");
|
|
if (IS_ERR(clk))
|
|
goto err;
|
|
|
|
clk_enable(clk);
|
|
|
|
clk = clk_lookup("enet_ref");
|
|
if (IS_ERR(clk))
|
|
goto err;
|
|
clk_enable(clk);
|
|
|
|
clk = clk_lookup("enet2_ref_125m");
|
|
if (IS_ERR(clk))
|
|
goto err;
|
|
|
|
clk_enable(clk);
|
|
|
|
val = readl(gprbase + IOMUXC_GPR1);
|
|
/* Use 125M anatop loopback REF_CLK1 for ENET1, clear gpr1[13], gpr1[17]*/
|
|
val &= ~(1 << 13);
|
|
val &= ~(1 << 17);
|
|
/* Use 125M anatop loopback REF_CLK1 for ENET2, clear gpr1[14], gpr1[18]*/
|
|
val &= ~(1 << 14);
|
|
val &= ~(1 << 18);
|
|
writel(val, gprbase + IOMUXC_GPR1);
|
|
|
|
/* Enable the ENET power, active low */
|
|
gpio_direction_output(IMX_GPIO_NR(2, 6), 0);
|
|
|
|
/* Reset AR8031 PHY */
|
|
gpio_direction_output(IMX_GPIO_NR(2, 7), 0);
|
|
udelay(500);
|
|
gpio_set_value(IMX_GPIO_NR(2, 7), 1);
|
|
|
|
return 0;
|
|
err:
|
|
pr_err("Setting up DFEC\n");
|
|
|
|
return -EIO;
|
|
}
|
|
|
|
static int imx6sx_sdb_coredevices_init(void)
|
|
{
|
|
if (!of_machine_is_compatible("fsl,imx6sx-sdb"))
|
|
return 0;
|
|
|
|
imx6sx_sdb_setup_fec();
|
|
|
|
imx6_bbu_internal_mmc_register_handler("sd", "/dev/mmc3",
|
|
BBU_HANDLER_FLAG_DEFAULT);
|
|
|
|
return 0;
|
|
}
|
|
console_initcall(imx6sx_sdb_coredevices_init);
|