1/* $OpenBSD: imxiic_fdt.c,v 1.3 2022/04/06 18:59:28 naddy Exp $ */ 2/* 3 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/param.h> 19#include <sys/device.h> 20#include <sys/kernel.h> 21#include <sys/systm.h> 22 23#include <machine/bus.h> 24#include <machine/fdt.h> 25 26#include <dev/ofw/openfirm.h> 27#include <dev/ofw/ofw_clock.h> 28#include <dev/ofw/ofw_pinctrl.h> 29#include <dev/ofw/fdt.h> 30 31#include <dev/ic/imxiicvar.h> 32 33struct imxiic_fdt_softc { 34 struct imxiic_softc fc_sc; 35 int fc_node; 36}; 37 38int imxiic_fdt_match(struct device *, void *, void *); 39void imxiic_fdt_attach(struct device *, struct device *, void *); 40 41void imxiic_fdt_bus_scan(struct device *, struct i2cbus_attach_args *, void *); 42 43const struct cfattach imxiic_fdt_ca = { 44 sizeof(struct imxiic_fdt_softc), imxiic_fdt_match, imxiic_fdt_attach 45}; 46 47int 48imxiic_fdt_match(struct device *parent, void *match, void *aux) 49{ 50 struct fdt_attach_args *faa = aux; 51 52 return (OF_is_compatible(faa->fa_node, "fsl,imx21-i2c") || 53 OF_is_compatible(faa->fa_node, "fsl,vf610-i2c")); 54} 55 56void 57imxiic_fdt_attach(struct device *parent, struct device *self, void *aux) 58{ 59 struct imxiic_fdt_softc *fc = (struct imxiic_fdt_softc *)self; 60 struct imxiic_softc *sc = &fc->fc_sc; 61 struct fdt_attach_args *faa = aux; 62 63 if (faa->fa_nreg < 1) 64 return; 65 66 sc->sc_iot = faa->fa_iot; 67 sc->sc_ios = faa->fa_reg[0].size; 68 fc->fc_node = faa->fa_node; 69 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 70 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 71 panic("imxiic_attach: bus_space_map failed!"); 72 73 sc->sc_reg_shift = 2; 74 sc->sc_clk_div = imxiic_imx21_clk_div; 75 sc->sc_clk_ndiv = nitems(imxiic_imx21_clk_div); 76 sc->sc_type = I2C_TYPE_IMX21; 77 78 if (OF_is_compatible(faa->fa_node, "fsl,vf610-i2c")) { 79 sc->sc_reg_shift = 0; 80 sc->sc_clk_div = imxiic_vf610_clk_div; 81 sc->sc_clk_ndiv = nitems(imxiic_vf610_clk_div); 82 sc->sc_type = I2C_TYPE_VF610; 83 } 84 85 printf("\n"); 86 87 clock_enable(faa->fa_node, NULL); 88 pinctrl_byname(faa->fa_node, "default"); 89 90 /* set speed */ 91 sc->sc_clkrate = clock_get_frequency(fc->fc_node, NULL) / 1000; 92 sc->sc_bitrate = OF_getpropint(fc->fc_node, 93 "clock-frequency", 100000) / 1000; 94 imxiic_setspeed(sc, sc->sc_bitrate); 95 96 /* reset */ 97 imxiic_enable(sc, 0); 98 99 sc->stopped = 1; 100 rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); 101 102 struct i2cbus_attach_args iba; 103 104 sc->i2c_tag.ic_cookie = sc; 105 sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus; 106 sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus; 107 sc->i2c_tag.ic_exec = imxiic_i2c_exec; 108 109 bzero(&iba, sizeof iba); 110 iba.iba_name = "iic"; 111 iba.iba_tag = &sc->i2c_tag; 112 iba.iba_bus_scan = imxiic_fdt_bus_scan; 113 iba.iba_bus_scan_arg = &fc->fc_node; 114 config_found(&sc->sc_dev, &iba, iicbus_print); 115} 116 117void 118imxiic_fdt_bus_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux) 119{ 120 int iba_node = *(int *)aux; 121 extern int iic_print(void *, const char *); 122 struct i2c_attach_args ia; 123 char name[32], status[32]; 124 uint32_t reg[1]; 125 int node; 126 127 for (node = OF_child(iba_node); node; node = OF_peer(node)) { 128 memset(name, 0, sizeof(name)); 129 memset(status, 0, sizeof(status)); 130 memset(reg, 0, sizeof(reg)); 131 132 if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) 133 continue; 134 if (name[0] == '\0') 135 continue; 136 137 if (OF_getprop(node, "status", status, sizeof(status)) > 0 && 138 strcmp(status, "disabled") == 0) 139 continue; 140 141 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 142 continue; 143 144 memset(&ia, 0, sizeof(ia)); 145 ia.ia_tag = iba->iba_tag; 146 ia.ia_addr = bemtoh32(®[0]); 147 ia.ia_name = name; 148 ia.ia_cookie = &node; 149 150 config_found(self, &ia, iic_print); 151 } 152} 153