Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.6 317 lines 8.6 kB view raw
1/* 2 * Renesas R-Car Gen3 for USB2.0 PHY driver 3 * 4 * Copyright (C) 2015 Renesas Electronics Corporation 5 * 6 * This is based on the phy-rcar-gen2 driver: 7 * Copyright (C) 2014 Renesas Solutions Corp. 8 * Copyright (C) 2014 Cogent Embedded, Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15#include <linux/interrupt.h> 16#include <linux/io.h> 17#include <linux/module.h> 18#include <linux/of.h> 19#include <linux/of_address.h> 20#include <linux/phy/phy.h> 21#include <linux/platform_device.h> 22 23/******* USB2.0 Host registers (original offset is +0x200) *******/ 24#define USB2_INT_ENABLE 0x000 25#define USB2_USBCTR 0x00c 26#define USB2_SPD_RSM_TIMSET 0x10c 27#define USB2_OC_TIMSET 0x110 28#define USB2_COMMCTRL 0x600 29#define USB2_OBINTSTA 0x604 30#define USB2_OBINTEN 0x608 31#define USB2_VBCTRL 0x60c 32#define USB2_LINECTRL1 0x610 33#define USB2_ADPCTRL 0x630 34 35/* INT_ENABLE */ 36#define USB2_INT_ENABLE_UCOM_INTEN BIT(3) 37#define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) 38#define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) 39#define USB2_INT_ENABLE_INIT (USB2_INT_ENABLE_UCOM_INTEN | \ 40 USB2_INT_ENABLE_USBH_INTB_EN | \ 41 USB2_INT_ENABLE_USBH_INTA_EN) 42 43/* USBCTR */ 44#define USB2_USBCTR_DIRPD BIT(2) 45#define USB2_USBCTR_PLL_RST BIT(1) 46 47/* SPD_RSM_TIMSET */ 48#define USB2_SPD_RSM_TIMSET_INIT 0x014e029b 49 50/* OC_TIMSET */ 51#define USB2_OC_TIMSET_INIT 0x000209ab 52 53/* COMMCTRL */ 54#define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */ 55 56/* OBINTSTA and OBINTEN */ 57#define USB2_OBINT_SESSVLDCHG BIT(12) 58#define USB2_OBINT_IDDIGCHG BIT(11) 59#define USB2_OBINT_BITS (USB2_OBINT_SESSVLDCHG | \ 60 USB2_OBINT_IDDIGCHG) 61 62/* VBCTRL */ 63#define USB2_VBCTRL_DRVVBUSSEL BIT(8) 64 65/* LINECTRL1 */ 66#define USB2_LINECTRL1_DPRPD_EN BIT(19) 67#define USB2_LINECTRL1_DP_RPD BIT(18) 68#define USB2_LINECTRL1_DMRPD_EN BIT(17) 69#define USB2_LINECTRL1_DM_RPD BIT(16) 70 71/* ADPCTRL */ 72#define USB2_ADPCTRL_OTGSESSVLD BIT(20) 73#define USB2_ADPCTRL_IDDIG BIT(19) 74#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ 75#define USB2_ADPCTRL_DRVVBUS BIT(4) 76 77struct rcar_gen3_data { 78 void __iomem *base; 79 struct clk *clk; 80}; 81 82struct rcar_gen3_chan { 83 struct rcar_gen3_data usb2; 84 struct phy *phy; 85 bool has_otg; 86}; 87 88static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) 89{ 90 void __iomem *usb2_base = ch->usb2.base; 91 u32 val = readl(usb2_base + USB2_COMMCTRL); 92 93 dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host); 94 if (host) 95 val &= ~USB2_COMMCTRL_OTG_PERI; 96 else 97 val |= USB2_COMMCTRL_OTG_PERI; 98 writel(val, usb2_base + USB2_COMMCTRL); 99} 100 101static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) 102{ 103 void __iomem *usb2_base = ch->usb2.base; 104 u32 val = readl(usb2_base + USB2_LINECTRL1); 105 106 dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); 107 val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); 108 if (dp) 109 val |= USB2_LINECTRL1_DP_RPD; 110 if (dm) 111 val |= USB2_LINECTRL1_DM_RPD; 112 writel(val, usb2_base + USB2_LINECTRL1); 113} 114 115static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) 116{ 117 void __iomem *usb2_base = ch->usb2.base; 118 u32 val = readl(usb2_base + USB2_ADPCTRL); 119 120 dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus); 121 if (vbus) 122 val |= USB2_ADPCTRL_DRVVBUS; 123 else 124 val &= ~USB2_ADPCTRL_DRVVBUS; 125 writel(val, usb2_base + USB2_ADPCTRL); 126} 127 128static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) 129{ 130 rcar_gen3_set_linectrl(ch, 1, 1); 131 rcar_gen3_set_host_mode(ch, 1); 132 rcar_gen3_enable_vbus_ctrl(ch, 1); 133} 134 135static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) 136{ 137 rcar_gen3_set_linectrl(ch, 0, 1); 138 rcar_gen3_set_host_mode(ch, 0); 139 rcar_gen3_enable_vbus_ctrl(ch, 0); 140} 141 142static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch) 143{ 144 return !!(readl(ch->usb2.base + USB2_ADPCTRL) & 145 USB2_ADPCTRL_OTGSESSVLD); 146} 147 148static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) 149{ 150 return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); 151} 152 153static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) 154{ 155 bool is_host = true; 156 157 /* B-device? */ 158 if (rcar_gen3_check_id(ch) && rcar_gen3_check_vbus(ch)) 159 is_host = false; 160 161 if (is_host) 162 rcar_gen3_init_for_host(ch); 163 else 164 rcar_gen3_init_for_peri(ch); 165} 166 167static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) 168{ 169 void __iomem *usb2_base = ch->usb2.base; 170 u32 val; 171 172 val = readl(usb2_base + USB2_VBCTRL); 173 writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); 174 writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); 175 val = readl(usb2_base + USB2_OBINTEN); 176 writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); 177 val = readl(usb2_base + USB2_ADPCTRL); 178 writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); 179 val = readl(usb2_base + USB2_LINECTRL1); 180 rcar_gen3_set_linectrl(ch, 0, 0); 181 writel(val | USB2_LINECTRL1_DPRPD_EN | USB2_LINECTRL1_DMRPD_EN, 182 usb2_base + USB2_LINECTRL1); 183 184 rcar_gen3_device_recognition(ch); 185} 186 187static int rcar_gen3_phy_usb2_init(struct phy *p) 188{ 189 struct rcar_gen3_chan *channel = phy_get_drvdata(p); 190 void __iomem *usb2_base = channel->usb2.base; 191 192 /* Initialize USB2 part */ 193 writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); 194 writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); 195 writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); 196 197 /* Initialize otg part */ 198 if (channel->has_otg) 199 rcar_gen3_init_otg(channel); 200 201 return 0; 202} 203 204static int rcar_gen3_phy_usb2_exit(struct phy *p) 205{ 206 struct rcar_gen3_chan *channel = phy_get_drvdata(p); 207 208 writel(0, channel->usb2.base + USB2_INT_ENABLE); 209 210 return 0; 211} 212 213static int rcar_gen3_phy_usb2_power_on(struct phy *p) 214{ 215 struct rcar_gen3_chan *channel = phy_get_drvdata(p); 216 void __iomem *usb2_base = channel->usb2.base; 217 u32 val; 218 219 val = readl(usb2_base + USB2_USBCTR); 220 val |= USB2_USBCTR_PLL_RST; 221 writel(val, usb2_base + USB2_USBCTR); 222 val &= ~USB2_USBCTR_PLL_RST; 223 writel(val, usb2_base + USB2_USBCTR); 224 225 return 0; 226} 227 228static struct phy_ops rcar_gen3_phy_usb2_ops = { 229 .init = rcar_gen3_phy_usb2_init, 230 .exit = rcar_gen3_phy_usb2_exit, 231 .power_on = rcar_gen3_phy_usb2_power_on, 232 .owner = THIS_MODULE, 233}; 234 235static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) 236{ 237 struct rcar_gen3_chan *ch = _ch; 238 void __iomem *usb2_base = ch->usb2.base; 239 u32 status = readl(usb2_base + USB2_OBINTSTA); 240 irqreturn_t ret = IRQ_NONE; 241 242 if (status & USB2_OBINT_BITS) { 243 dev_vdbg(&ch->phy->dev, "%s: %08x\n", __func__, status); 244 writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); 245 rcar_gen3_device_recognition(ch); 246 ret = IRQ_HANDLED; 247 } 248 249 return ret; 250} 251 252static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { 253 { .compatible = "renesas,usb2-phy-r8a7795" }, 254 { } 255}; 256MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); 257 258static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) 259{ 260 struct device *dev = &pdev->dev; 261 struct rcar_gen3_chan *channel; 262 struct phy_provider *provider; 263 struct resource *res; 264 int irq; 265 266 if (!dev->of_node) { 267 dev_err(dev, "This driver needs device tree\n"); 268 return -EINVAL; 269 } 270 271 channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL); 272 if (!channel) 273 return -ENOMEM; 274 275 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 276 channel->usb2.base = devm_ioremap_resource(dev, res); 277 if (IS_ERR(channel->usb2.base)) 278 return PTR_ERR(channel->usb2.base); 279 280 /* call request_irq for OTG */ 281 irq = platform_get_irq(pdev, 0); 282 if (irq >= 0) { 283 irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, 284 IRQF_SHARED, dev_name(dev), channel); 285 if (irq < 0) 286 dev_err(dev, "No irq handler (%d)\n", irq); 287 channel->has_otg = true; 288 } 289 290 /* devm_phy_create() will call pm_runtime_enable(dev); */ 291 channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops); 292 if (IS_ERR(channel->phy)) { 293 dev_err(dev, "Failed to create USB2 PHY\n"); 294 return PTR_ERR(channel->phy); 295 } 296 297 phy_set_drvdata(channel->phy, channel); 298 299 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 300 if (IS_ERR(provider)) 301 dev_err(dev, "Failed to register PHY provider\n"); 302 303 return PTR_ERR_OR_ZERO(provider); 304} 305 306static struct platform_driver rcar_gen3_phy_usb2_driver = { 307 .driver = { 308 .name = "phy_rcar_gen3_usb2", 309 .of_match_table = rcar_gen3_phy_usb2_match_table, 310 }, 311 .probe = rcar_gen3_phy_usb2_probe, 312}; 313module_platform_driver(rcar_gen3_phy_usb2_driver); 314 315MODULE_LICENSE("GPL v2"); 316MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 2.0 PHY"); 317MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");