/*1* Copyright (c) 20102* Ben Gray <[email protected]>.3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13* 3. All advertising materials mentioning features or use of this software14* must display the following acknowledgement:15* This product includes software developed by Ben Gray.16* 4. The name of the company nor the name of the author may be used to17* endorse or promote products derived from this software without specific18* prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR21* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES22* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.23* IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,24* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,25* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;26* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,27* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR28* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF29* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132/**33* Exposes pinmux module to pinctrl-compatible interface34*/3536#include <sys/param.h>37#include <sys/systm.h>38#include <sys/kernel.h>39#include <sys/module.h>40#include <sys/bus.h>41#include <sys/resource.h>42#include <sys/rman.h>43#include <sys/lock.h>44#include <sys/mutex.h>4546#include <machine/bus.h>47#include <machine/resource.h>4849#include <dev/ofw/openfirm.h>50#include <dev/ofw/ofw_bus.h>51#include <dev/ofw/ofw_bus_subr.h>52#include <dev/fdt/fdt_pinctrl.h>5354#include <arm/ti/am335x/am335x_scm_padconf.h>55#include <arm/ti/ti_cpuid.h>56#include "ti_pinmux.h"5758struct pincfg {59uint32_t reg;60uint32_t conf;61};6263static struct resource_spec ti_pinmux_res_spec[] = {64{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */65{ -1, 0 }66};6768static struct ti_pinmux_softc *ti_pinmux_sc;6970#define ti_pinmux_read_2(sc, reg) \71bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg))72#define ti_pinmux_write_2(sc, reg, val) \73bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))74#define ti_pinmux_read_4(sc, reg) \75bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))76#define ti_pinmux_write_4(sc, reg, val) \77bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))7879/**80* ti_padconf_devmap - Array of pins, should be defined one per SoC81*82* This array is typically defined in one of the targeted *_scm_pinumx.c83* files and is specific to the given SoC platform. Each entry in the array84* corresponds to an individual pin.85*/86static const struct ti_pinmux_device *ti_pinmux_dev;8788/**89* ti_pinmux_padconf_from_name - searches the list of pads and returns entry90* with matching ball name.91* @ballname: the name of the ball92*93* RETURNS:94* A pointer to the matching padconf or NULL if the ball wasn't found.95*/96static const struct ti_pinmux_padconf*97ti_pinmux_padconf_from_name(const char *ballname)98{99const struct ti_pinmux_padconf *padconf;100101padconf = ti_pinmux_dev->padconf;102while (padconf->ballname != NULL) {103if (strcmp(ballname, padconf->ballname) == 0)104return(padconf);105padconf++;106}107108return (NULL);109}110111/**112* ti_pinmux_padconf_set_internal - sets the muxmode and state for a pad/pin113* @padconf: pointer to the pad structure114* @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"115* @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???116*117*118* LOCKING:119* Internally locks it's own context.120*121* RETURNS:122* 0 on success.123* EINVAL if pin requested is outside valid range or already in use.124*/125static int126ti_pinmux_padconf_set_internal(struct ti_pinmux_softc *sc,127const struct ti_pinmux_padconf *padconf,128const char *muxmode, unsigned int state)129{130unsigned int mode;131uint16_t reg_val;132133/* populate the new value for the PADCONF register */134reg_val = (uint16_t)(state & ti_pinmux_dev->padconf_sate_mask);135136/* find the new mode requested */137for (mode = 0; mode < 8; mode++) {138if ((padconf->muxmodes[mode] != NULL) &&139(strcmp(padconf->muxmodes[mode], muxmode) == 0)) {140break;141}142}143144/* couldn't find the mux mode */145if (mode >= 8) {146printf("Invalid mode \"%s\"\n", muxmode);147return (EINVAL);148}149150/* set the mux mode */151reg_val |= (uint16_t)(mode & ti_pinmux_dev->padconf_muxmode_mask);152153if (bootverbose)154device_printf(sc->sc_dev, "setting internal %x for %s\n",155reg_val, muxmode);156/* write the register value (16-bit writes) */157ti_pinmux_write_2(sc, padconf->reg_off, reg_val);158159return (0);160}161162/**163* ti_pinmux_padconf_set - sets the muxmode and state for a pad/pin164* @padname: the name of the pad, i.e. "c12"165* @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"166* @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???167*168*169* LOCKING:170* Internally locks it's own context.171*172* RETURNS:173* 0 on success.174* EINVAL if pin requested is outside valid range or already in use.175*/176int177ti_pinmux_padconf_set(const char *padname, const char *muxmode, unsigned int state)178{179const struct ti_pinmux_padconf *padconf;180181if (!ti_pinmux_sc)182return (ENXIO);183184/* find the pin in the devmap */185padconf = ti_pinmux_padconf_from_name(padname);186if (padconf == NULL)187return (EINVAL);188189return (ti_pinmux_padconf_set_internal(ti_pinmux_sc, padconf, muxmode, state));190}191192/**193* ti_pinmux_padconf_get - gets the muxmode and state for a pad/pin194* @padname: the name of the pad, i.e. "c12"195* @muxmode: upon return will contain the name of the muxmode of the pin196* @state: upon return will contain the state of the pad/pin197*198*199* LOCKING:200* Internally locks it's own context.201*202* RETURNS:203* 0 on success.204* EINVAL if pin requested is outside valid range or already in use.205*/206int207ti_pinmux_padconf_get(const char *padname, const char **muxmode,208unsigned int *state)209{210const struct ti_pinmux_padconf *padconf;211uint16_t reg_val;212213if (!ti_pinmux_sc)214return (ENXIO);215216/* find the pin in the devmap */217padconf = ti_pinmux_padconf_from_name(padname);218if (padconf == NULL)219return (EINVAL);220221/* read the register value (16-bit reads) */222reg_val = ti_pinmux_read_2(ti_pinmux_sc, padconf->reg_off);223224/* save the state */225if (state)226*state = (reg_val & ti_pinmux_dev->padconf_sate_mask);227228/* save the mode */229if (muxmode)230*muxmode = padconf->muxmodes[(reg_val & ti_pinmux_dev->padconf_muxmode_mask)];231232return (0);233}234235/**236* ti_pinmux_padconf_set_gpiomode - converts a pad to GPIO mode.237* @gpio: the GPIO pin number (0-195)238* @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???239*240*241*242* LOCKING:243* Internally locks it's own context.244*245* RETURNS:246* 0 on success.247* EINVAL if pin requested is outside valid range or already in use.248*/249int250ti_pinmux_padconf_set_gpiomode(uint32_t gpio, unsigned int state)251{252const struct ti_pinmux_padconf *padconf;253uint16_t reg_val;254255if (!ti_pinmux_sc)256return (ENXIO);257258/* find the gpio pin in the padconf array */259padconf = ti_pinmux_dev->padconf;260while (padconf->ballname != NULL) {261if (padconf->gpio_pin == gpio)262break;263padconf++;264}265if (padconf->ballname == NULL)266return (EINVAL);267268/* populate the new value for the PADCONF register */269reg_val = (uint16_t)(state & ti_pinmux_dev->padconf_sate_mask);270271/* set the mux mode */272reg_val |= (uint16_t)(padconf->gpio_mode & ti_pinmux_dev->padconf_muxmode_mask);273274/* write the register value (16-bit writes) */275ti_pinmux_write_2(ti_pinmux_sc, padconf->reg_off, reg_val);276277return (0);278}279280/**281* ti_pinmux_padconf_get_gpiomode - gets the current GPIO mode of the pin282* @gpio: the GPIO pin number (0-195)283* @state: upon return will contain the state284*285*286*287* LOCKING:288* Internally locks it's own context.289*290* RETURNS:291* 0 on success.292* EINVAL if pin requested is outside valid range or not configured as GPIO.293*/294int295ti_pinmux_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)296{297const struct ti_pinmux_padconf *padconf;298uint16_t reg_val;299300if (!ti_pinmux_sc)301return (ENXIO);302303/* find the gpio pin in the padconf array */304padconf = ti_pinmux_dev->padconf;305while (padconf->ballname != NULL) {306if (padconf->gpio_pin == gpio)307break;308padconf++;309}310if (padconf->ballname == NULL)311return (EINVAL);312313/* read the current register settings */314reg_val = ti_pinmux_read_2(ti_pinmux_sc, padconf->reg_off);315316/* check to make sure the pins is configured as GPIO in the first state */317if ((reg_val & ti_pinmux_dev->padconf_muxmode_mask) != padconf->gpio_mode)318return (EINVAL);319320/* read and store the reset of the state, i.e. pull-up, pull-down, etc */321if (state)322*state = (reg_val & ti_pinmux_dev->padconf_sate_mask);323324return (0);325}326327static int328ti_pinmux_configure_pins(device_t dev, phandle_t cfgxref)329{330struct pincfg *cfgtuples, *cfg;331phandle_t cfgnode;332int i, ntuples;333static struct ti_pinmux_softc *sc;334335sc = device_get_softc(dev);336cfgnode = OF_node_from_xref(cfgxref);337ntuples = OF_getencprop_alloc_multi(cfgnode, "pinctrl-single,pins",338sizeof(*cfgtuples), (void **)&cfgtuples);339340if (ntuples < 0)341return (ENOENT);342343if (ntuples == 0)344return (0); /* Empty property is not an error. */345346for (i = 0, cfg = cfgtuples; i < ntuples; i++, cfg++) {347if (bootverbose) {348char name[32];349OF_getprop(cfgnode, "name", &name, sizeof(name));350printf("%16s: muxreg 0x%04x muxval 0x%02x\n",351name, cfg->reg, cfg->conf);352}353354/* write the register value (16-bit writes) */355ti_pinmux_write_2(sc, cfg->reg, cfg->conf);356}357358OF_prop_free(cfgtuples);359360return (0);361}362363/*364* Device part of OMAP SCM driver365*/366367static int368ti_pinmux_probe(device_t dev)369{370if (!ofw_bus_status_okay(dev))371return (ENXIO);372373if (!ofw_bus_is_compatible(dev, "pinctrl-single"))374return (ENXIO);375376if (ti_pinmux_sc) {377printf("%s: multiple pinctrl modules in device tree data, ignoring\n",378__func__);379return (EEXIST);380}381switch (ti_chip()) {382#ifdef SOC_TI_AM335X383case CHIP_AM335X:384ti_pinmux_dev = &ti_am335x_pinmux_dev;385break;386#endif387default:388printf("Unknown CPU in pinmux\n");389return (ENXIO);390}391392device_set_desc(dev, "TI Pinmux Module");393return (BUS_PROBE_DEFAULT);394}395396/**397* ti_pinmux_attach - attaches the pinmux to the simplebus398* @dev: new device399*400* RETURNS401* Zero on success or ENXIO if an error occuried.402*/403static int404ti_pinmux_attach(device_t dev)405{406struct ti_pinmux_softc *sc = device_get_softc(dev);407408#if 0409if (ti_pinmux_sc)410return (ENXIO);411#endif412413sc->sc_dev = dev;414415if (bus_alloc_resources(dev, ti_pinmux_res_spec, sc->sc_res)) {416device_printf(dev, "could not allocate resources\n");417return (ENXIO);418}419420sc->sc_bst = rman_get_bustag(sc->sc_res[0]);421sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);422423if (ti_pinmux_sc == NULL)424ti_pinmux_sc = sc;425426fdt_pinctrl_register(dev, "pinctrl-single,pins");427fdt_pinctrl_configure_tree(dev);428429return (0);430}431432static device_method_t ti_pinmux_methods[] = {433DEVMETHOD(device_probe, ti_pinmux_probe),434DEVMETHOD(device_attach, ti_pinmux_attach),435436/* fdt_pinctrl interface */437DEVMETHOD(fdt_pinctrl_configure, ti_pinmux_configure_pins),438{ 0, 0 }439};440441static driver_t ti_pinmux_driver = {442"ti_pinmux",443ti_pinmux_methods,444sizeof(struct ti_pinmux_softc),445};446447DRIVER_MODULE(ti_pinmux, simplebus, ti_pinmux_driver, 0, 0);448MODULE_VERSION(ti_pinmux, 1);449MODULE_DEPEND(ti_pinmux, ti_scm, 1, 1, 1);450451452