brintos

brintos / linux-shallow public Read only

0
0
Text · 16.1 KiB · 7bbf729 Raw
720 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Motorola CPCAP PMIC USB PHY driver4 * Copyright (C) 2017 Tony Lindgren <tony@atomide.com>5 *6 * Some parts based on earlier Motorola Linux kernel tree code in7 * board-mapphone-usb.c and cpcap-usb-det.c:8 * Copyright (C) 2007 - 2011 Motorola, Inc.9 */10 11#include <linux/atomic.h>12#include <linux/clk.h>13#include <linux/delay.h>14#include <linux/err.h>15#include <linux/io.h>16#include <linux/module.h>17#include <linux/of.h>18#include <linux/iio/consumer.h>19#include <linux/pinctrl/consumer.h>20#include <linux/platform_device.h>21#include <linux/regmap.h>22#include <linux/slab.h>23 24#include <linux/gpio/consumer.h>25#include <linux/mfd/motorola-cpcap.h>26#include <linux/phy/omap_usb.h>27#include <linux/phy/phy.h>28#include <linux/regulator/consumer.h>29#include <linux/usb/musb.h>30 31/* CPCAP_REG_USBC1 register bits */32#define CPCAP_BIT_IDPULSE		BIT(15)33#define CPCAP_BIT_ID100KPU		BIT(14)34#define CPCAP_BIT_IDPUCNTRL		BIT(13)35#define CPCAP_BIT_IDPU			BIT(12)36#define CPCAP_BIT_IDPD			BIT(11)37#define CPCAP_BIT_VBUSCHRGTMR3		BIT(10)38#define CPCAP_BIT_VBUSCHRGTMR2		BIT(9)39#define CPCAP_BIT_VBUSCHRGTMR1		BIT(8)40#define CPCAP_BIT_VBUSCHRGTMR0		BIT(7)41#define CPCAP_BIT_VBUSPU		BIT(6)42#define CPCAP_BIT_VBUSPD		BIT(5)43#define CPCAP_BIT_DMPD			BIT(4)44#define CPCAP_BIT_DPPD			BIT(3)45#define CPCAP_BIT_DM1K5PU		BIT(2)46#define CPCAP_BIT_DP1K5PU		BIT(1)47#define CPCAP_BIT_DP150KPU		BIT(0)48 49/* CPCAP_REG_USBC2 register bits */50#define CPCAP_BIT_ZHSDRV1		BIT(15)51#define CPCAP_BIT_ZHSDRV0		BIT(14)52#define CPCAP_BIT_DPLLCLKREQ		BIT(13)53#define CPCAP_BIT_SE0CONN		BIT(12)54#define CPCAP_BIT_UARTTXTRI		BIT(11)55#define CPCAP_BIT_UARTSWAP		BIT(10)56#define CPCAP_BIT_UARTMUX1		BIT(9)57#define CPCAP_BIT_UARTMUX0		BIT(8)58#define CPCAP_BIT_ULPISTPLOW		BIT(7)59#define CPCAP_BIT_TXENPOL		BIT(6)60#define CPCAP_BIT_USBXCVREN		BIT(5)61#define CPCAP_BIT_USBCNTRL		BIT(4)62#define CPCAP_BIT_USBSUSPEND		BIT(3)63#define CPCAP_BIT_EMUMODE2		BIT(2)64#define CPCAP_BIT_EMUMODE1		BIT(1)65#define CPCAP_BIT_EMUMODE0		BIT(0)66 67/* CPCAP_REG_USBC3 register bits */68#define CPCAP_BIT_SPARE_898_15		BIT(15)69#define CPCAP_BIT_IHSTX03		BIT(14)70#define CPCAP_BIT_IHSTX02		BIT(13)71#define CPCAP_BIT_IHSTX01		BIT(12)72#define CPCAP_BIT_IHSTX0		BIT(11)73#define CPCAP_BIT_IDPU_SPI		BIT(10)74#define CPCAP_BIT_UNUSED_898_9		BIT(9)75#define CPCAP_BIT_VBUSSTBY_EN		BIT(8)76#define CPCAP_BIT_VBUSEN_SPI		BIT(7)77#define CPCAP_BIT_VBUSPU_SPI		BIT(6)78#define CPCAP_BIT_VBUSPD_SPI		BIT(5)79#define CPCAP_BIT_DMPD_SPI		BIT(4)80#define CPCAP_BIT_DPPD_SPI		BIT(3)81#define CPCAP_BIT_SUSPEND_SPI		BIT(2)82#define CPCAP_BIT_PU_SPI		BIT(1)83#define CPCAP_BIT_ULPI_SPI_SEL		BIT(0)84 85struct cpcap_usb_ints_state {86	bool id_ground;87	bool id_float;88	bool chrg_det;89	bool rvrs_chrg;90	bool vbusov;91 92	bool chrg_se1b;93	bool se0conn;94	bool rvrs_mode;95	bool chrgcurr1;96	bool vbusvld;97	bool sessvld;98	bool sessend;99	bool se1;100 101	bool battdetb;102	bool dm;103	bool dp;104};105 106enum cpcap_gpio_mode {107	CPCAP_DM_DP,108	CPCAP_MDM_RX_TX,109	CPCAP_UNKNOWN_DISABLED,	/* Seems to disable USB lines */110	CPCAP_OTG_DM_DP,111};112 113struct cpcap_phy_ddata {114	struct regmap *reg;115	struct device *dev;116	struct usb_phy phy;117	struct delayed_work detect_work;118	struct pinctrl *pins;119	struct pinctrl_state *pins_ulpi;120	struct pinctrl_state *pins_utmi;121	struct pinctrl_state *pins_uart;122	struct gpio_desc *gpio[2];123	struct iio_channel *vbus;124	struct iio_channel *id;125	struct regulator *vusb;126	atomic_t active;127	unsigned int vbus_provider:1;128	unsigned int docked:1;129};130 131static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata)132{133	int error, value = 0;134 135	error = iio_read_channel_processed(ddata->vbus, &value);136	if (error >= 0)137		return value > 3900;138 139	dev_err(ddata->dev, "error reading VBUS: %i\n", error);140 141	return false;142}143 144static int cpcap_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host)145{146	otg->host = host;147	if (!host)148		otg->state = OTG_STATE_UNDEFINED;149 150	return 0;151}152 153static int cpcap_usb_phy_set_peripheral(struct usb_otg *otg,154					struct usb_gadget *gadget)155{156	otg->gadget = gadget;157	if (!gadget)158		otg->state = OTG_STATE_UNDEFINED;159 160	return 0;161}162 163static const struct phy_ops ops = {164	.owner		= THIS_MODULE,165};166 167static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata,168				    struct cpcap_usb_ints_state *s)169{170	int val, error;171 172	error = regmap_read(ddata->reg, CPCAP_REG_INTS1, &val);173	if (error)174		return error;175 176	s->id_ground = val & BIT(15);177	s->id_float = val & BIT(14);178	s->vbusov = val & BIT(11);179 180	error = regmap_read(ddata->reg, CPCAP_REG_INTS2, &val);181	if (error)182		return error;183 184	s->vbusvld = val & BIT(3);185	s->sessvld = val & BIT(2);186	s->sessend = val & BIT(1);187	s->se1 = val & BIT(0);188 189	error = regmap_read(ddata->reg, CPCAP_REG_INTS4, &val);190	if (error)191		return error;192 193	s->dm = val & BIT(1);194	s->dp = val & BIT(0);195 196	return 0;197}198 199static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata);200static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata);201 202static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata,203				       enum musb_vbus_id_status status)204{205	int error;206 207	error = musb_mailbox(status);208	if (!error)209		return;210 211	dev_dbg(ddata->dev, "%s: musb_mailbox failed: %i\n",212		__func__, error);213}214 215static void cpcap_usb_detect(struct work_struct *work)216{217	struct cpcap_phy_ddata *ddata;218	struct cpcap_usb_ints_state s;219	bool vbus = false;220	int error;221 222	ddata = container_of(work, struct cpcap_phy_ddata, detect_work.work);223 224	error = cpcap_phy_get_ints_state(ddata, &s);225	if (error)226		return;227 228	vbus = cpcap_usb_vbus_valid(ddata);229 230	/* We need to kick the VBUS as USB A-host */231	if (s.id_ground && ddata->vbus_provider) {232		dev_dbg(ddata->dev, "still in USB A-host mode, kicking VBUS\n");233 234		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);235 236		error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,237					   CPCAP_BIT_VBUSSTBY_EN |238					   CPCAP_BIT_VBUSEN_SPI,239					   CPCAP_BIT_VBUSEN_SPI);240		if (error)241			goto out_err;242 243		return;244	}245 246	if (vbus && s.id_ground && ddata->docked) {247		dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n");248 249		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);250 251		return;252	}253 254	/* No VBUS needed with docks */255	if (vbus && s.id_ground && !ddata->vbus_provider) {256		dev_dbg(ddata->dev, "connected to a dock\n");257 258		ddata->docked = true;259 260		error = cpcap_usb_set_usb_mode(ddata);261		if (error)262			goto out_err;263 264		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);265 266		/*267		 * Force check state again after musb has reoriented,268		 * otherwise devices won't enumerate after loading PHY269		 * driver.270		 */271		schedule_delayed_work(&ddata->detect_work,272				      msecs_to_jiffies(1000));273 274		return;275	}276 277	if (s.id_ground && !ddata->docked) {278		dev_dbg(ddata->dev, "id ground, USB host mode\n");279 280		ddata->vbus_provider = true;281 282		error = cpcap_usb_set_usb_mode(ddata);283		if (error)284			goto out_err;285 286		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);287 288		error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,289					   CPCAP_BIT_VBUSSTBY_EN |290					   CPCAP_BIT_VBUSEN_SPI,291					   CPCAP_BIT_VBUSEN_SPI);292		if (error)293			goto out_err;294 295		return;296	}297 298	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,299				   CPCAP_BIT_VBUSSTBY_EN |300				   CPCAP_BIT_VBUSEN_SPI, 0);301	if (error)302		goto out_err;303 304	vbus = cpcap_usb_vbus_valid(ddata);305 306	/* Otherwise assume we're connected to a USB host */307	if (vbus) {308		dev_dbg(ddata->dev, "connected to USB host\n");309		error = cpcap_usb_set_usb_mode(ddata);310		if (error)311			goto out_err;312		cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID);313 314		return;315	}316 317	ddata->vbus_provider = false;318	ddata->docked = false;319	cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);320 321	/* Default to debug UART mode */322	error = cpcap_usb_set_uart_mode(ddata);323	if (error)324		goto out_err;325 326	dev_dbg(ddata->dev, "set UART mode\n");327 328	return;329 330out_err:331	dev_err(ddata->dev, "error setting cable state: %i\n", error);332}333 334static irqreturn_t cpcap_phy_irq_thread(int irq, void *data)335{336	struct cpcap_phy_ddata *ddata = data;337 338	if (!atomic_read(&ddata->active))339		return IRQ_NONE;340 341	schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));342 343	return IRQ_HANDLED;344}345 346static int cpcap_usb_init_irq(struct platform_device *pdev,347			      struct cpcap_phy_ddata *ddata,348			      const char *name)349{350	int irq, error;351 352	irq = platform_get_irq_byname(pdev, name);353	if (irq < 0)354		return -ENODEV;355 356	error = devm_request_threaded_irq(ddata->dev, irq, NULL,357					  cpcap_phy_irq_thread,358					  IRQF_SHARED |359					  IRQF_ONESHOT,360					  name, ddata);361	if (error) {362		dev_err(ddata->dev, "could not get irq %s: %i\n",363			name, error);364 365		return error;366	}367 368	return 0;369}370 371static const char * const cpcap_phy_irqs[] = {372	/* REG_INT_0 */373	"id_ground", "id_float",374 375	/* REG_INT1 */376	"se0conn", "vbusvld", "sessvld", "sessend", "se1",377 378	/* REG_INT_3 */379	"dm", "dp",380};381 382static int cpcap_usb_init_interrupts(struct platform_device *pdev,383				     struct cpcap_phy_ddata *ddata)384{385	int i, error;386 387	for (i = 0; i < ARRAY_SIZE(cpcap_phy_irqs); i++) {388		error = cpcap_usb_init_irq(pdev, ddata, cpcap_phy_irqs[i]);389		if (error)390			return error;391	}392 393	return 0;394}395 396/*397 * Optional pins and modes. At least Motorola mapphone devices398 * are using two GPIOs and dynamic pinctrl to multiplex PHY pins399 * to UART, ULPI or UTMI mode.400 */401 402static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata,403				   enum cpcap_gpio_mode mode)404{405	if (!ddata->gpio[0] || !ddata->gpio[1])406		return 0;407 408	gpiod_set_value(ddata->gpio[0], mode & 1);409	gpiod_set_value(ddata->gpio[1], mode >> 1);410 411	return 0;412}413 414static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)415{416	int error;417 418	/* Disable lines to prevent glitches from waking up mdm6600 */419	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);420	if (error)421		goto out_err;422 423	if (ddata->pins_uart) {424		error = pinctrl_select_state(ddata->pins, ddata->pins_uart);425		if (error)426			goto out_err;427	}428 429	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,430				   CPCAP_BIT_VBUSPD,431				   CPCAP_BIT_VBUSPD);432	if (error)433		goto out_err;434 435	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,436				   0xffff, CPCAP_BIT_UARTMUX0 |437				   CPCAP_BIT_EMUMODE0);438	if (error)439		goto out_err;440 441	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, 0x7fff,442				   CPCAP_BIT_IDPU_SPI);443	if (error)444		goto out_err;445 446	/* Enable UART mode */447	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);448	if (error)449		goto out_err;450 451	return 0;452 453out_err:454	dev_err(ddata->dev, "%s failed with %i\n", __func__, error);455 456	return error;457}458 459static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)460{461	int error;462 463	/* Disable lines to prevent glitches from waking up mdm6600 */464	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);465	if (error)466		return error;467 468	if (ddata->pins_utmi) {469		error = pinctrl_select_state(ddata->pins, ddata->pins_utmi);470		if (error) {471			dev_err(ddata->dev, "could not set usb mode: %i\n",472				error);473 474			return error;475		}476	}477 478	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,479				   CPCAP_BIT_VBUSPD, 0);480	if (error)481		goto out_err;482 483	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,484				   CPCAP_BIT_PU_SPI |485				   CPCAP_BIT_DMPD_SPI |486				   CPCAP_BIT_DPPD_SPI |487				   CPCAP_BIT_SUSPEND_SPI |488				   CPCAP_BIT_ULPI_SPI_SEL, 0);489	if (error)490		goto out_err;491 492	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,493				   CPCAP_BIT_USBXCVREN,494				   CPCAP_BIT_USBXCVREN);495	if (error)496		goto out_err;497 498	/* Enable USB mode */499	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP);500	if (error)501		goto out_err;502 503	return 0;504 505out_err:506	dev_err(ddata->dev, "%s failed with %i\n", __func__, error);507 508	return error;509}510 511static int cpcap_usb_init_optional_pins(struct cpcap_phy_ddata *ddata)512{513	ddata->pins = devm_pinctrl_get(ddata->dev);514	if (IS_ERR(ddata->pins)) {515		dev_info(ddata->dev, "default pins not configured: %ld\n",516			 PTR_ERR(ddata->pins));517		ddata->pins = NULL;518 519		return 0;520	}521 522	ddata->pins_ulpi = pinctrl_lookup_state(ddata->pins, "ulpi");523	if (IS_ERR(ddata->pins_ulpi)) {524		dev_info(ddata->dev, "ulpi pins not configured\n");525		ddata->pins_ulpi = NULL;526	}527 528	ddata->pins_utmi = pinctrl_lookup_state(ddata->pins, "utmi");529	if (IS_ERR(ddata->pins_utmi)) {530		dev_info(ddata->dev, "utmi pins not configured\n");531		ddata->pins_utmi = NULL;532	}533 534	ddata->pins_uart = pinctrl_lookup_state(ddata->pins, "uart");535	if (IS_ERR(ddata->pins_uart)) {536		dev_info(ddata->dev, "uart pins not configured\n");537		ddata->pins_uart = NULL;538	}539 540	if (ddata->pins_uart)541		return pinctrl_select_state(ddata->pins, ddata->pins_uart);542 543	return 0;544}545 546static void cpcap_usb_init_optional_gpios(struct cpcap_phy_ddata *ddata)547{548	int i;549 550	for (i = 0; i < 2; i++) {551		ddata->gpio[i] = devm_gpiod_get_index(ddata->dev, "mode",552						      i, GPIOD_OUT_HIGH);553		if (IS_ERR(ddata->gpio[i])) {554			dev_info(ddata->dev, "no mode change GPIO%i: %li\n",555				 i, PTR_ERR(ddata->gpio[i]));556			ddata->gpio[i] = NULL;557		}558	}559}560 561static int cpcap_usb_init_iio(struct cpcap_phy_ddata *ddata)562{563	enum iio_chan_type type;564	int error;565 566	ddata->vbus = devm_iio_channel_get(ddata->dev, "vbus");567	if (IS_ERR(ddata->vbus)) {568		error = PTR_ERR(ddata->vbus);569		goto out_err;570	}571 572	if (!ddata->vbus->indio_dev) {573		error = -ENXIO;574		goto out_err;575	}576 577	error = iio_get_channel_type(ddata->vbus, &type);578	if (error < 0)579		goto out_err;580 581	if (type != IIO_VOLTAGE) {582		error = -EINVAL;583		goto out_err;584	}585 586	return 0;587 588out_err:589	dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",590		error);591 592	return error;593}594 595#ifdef CONFIG_OF596static const struct of_device_id cpcap_usb_phy_id_table[] = {597	{598		.compatible = "motorola,cpcap-usb-phy",599	},600	{601		.compatible = "motorola,mapphone-cpcap-usb-phy",602	},603	{},604};605MODULE_DEVICE_TABLE(of, cpcap_usb_phy_id_table);606#endif607 608static int cpcap_usb_phy_probe(struct platform_device *pdev)609{610	struct cpcap_phy_ddata *ddata;611	struct phy *generic_phy;612	struct phy_provider *phy_provider;613	struct usb_otg *otg;614	int error;615 616	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);617	if (!ddata)618		return -ENOMEM;619 620	ddata->reg = dev_get_regmap(pdev->dev.parent, NULL);621	if (!ddata->reg)622		return -ENODEV;623 624	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);625	if (!otg)626		return -ENOMEM;627 628	ddata->dev = &pdev->dev;629	ddata->phy.dev = ddata->dev;630	ddata->phy.label = "cpcap_usb_phy";631	ddata->phy.otg = otg;632	ddata->phy.type = USB_PHY_TYPE_USB2;633	otg->set_host = cpcap_usb_phy_set_host;634	otg->set_peripheral = cpcap_usb_phy_set_peripheral;635	otg->usb_phy = &ddata->phy;636	INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect);637	platform_set_drvdata(pdev, ddata);638 639	ddata->vusb = devm_regulator_get(&pdev->dev, "vusb");640	if (IS_ERR(ddata->vusb))641		return PTR_ERR(ddata->vusb);642 643	error = regulator_enable(ddata->vusb);644	if (error)645		return error;646 647	generic_phy = devm_phy_create(ddata->dev, NULL, &ops);648	if (IS_ERR(generic_phy)) {649		error = PTR_ERR(generic_phy);650		goto out_reg_disable;651	}652 653	phy_set_drvdata(generic_phy, ddata);654 655	phy_provider = devm_of_phy_provider_register(ddata->dev,656						     of_phy_simple_xlate);657	if (IS_ERR(phy_provider)) {658		error = PTR_ERR(phy_provider);659		goto out_reg_disable;660	}661 662	error = cpcap_usb_init_optional_pins(ddata);663	if (error)664		goto out_reg_disable;665 666	cpcap_usb_init_optional_gpios(ddata);667 668	error = cpcap_usb_init_iio(ddata);669	if (error)670		goto out_reg_disable;671 672	error = cpcap_usb_init_interrupts(pdev, ddata);673	if (error)674		goto out_reg_disable;675 676	usb_add_phy_dev(&ddata->phy);677	atomic_set(&ddata->active, 1);678	schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));679 680	return 0;681 682out_reg_disable:683	regulator_disable(ddata->vusb);684 685	return error;686}687 688static void cpcap_usb_phy_remove(struct platform_device *pdev)689{690	struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev);691	int error;692 693	atomic_set(&ddata->active, 0);694	error = cpcap_usb_set_uart_mode(ddata);695	if (error)696		dev_err(ddata->dev, "could not set UART mode\n");697 698	cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);699 700	usb_remove_phy(&ddata->phy);701	cancel_delayed_work_sync(&ddata->detect_work);702	regulator_disable(ddata->vusb);703}704 705static struct platform_driver cpcap_usb_phy_driver = {706	.probe		= cpcap_usb_phy_probe,707	.remove_new	= cpcap_usb_phy_remove,708	.driver		= {709		.name	= "cpcap-usb-phy",710		.of_match_table = of_match_ptr(cpcap_usb_phy_id_table),711	},712};713 714module_platform_driver(cpcap_usb_phy_driver);715 716MODULE_ALIAS("platform:cpcap_usb");717MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");718MODULE_DESCRIPTION("CPCAP usb phy driver");719MODULE_LICENSE("GPL v2");720